eBay大資料安全合規系列 - EB級叢集升級挑戰和實踐

語言: CN / TW / HK

作者|林意群

編輯|陳樂

供稿|DI Hadoop team

本文共5209字,預計閱讀時間13分鐘

更多幹貨請關注“eBay技術薈”公眾號

在上篇分享的文章【 eBay大資料安全合規系列 - 系統篇 】中,介紹了目前eBay大資料平臺在安全合規方面遇到的挑戰和困難,以及我們如何在系統平臺的層面對此進行改進,最終實現了在保證升級速率的情況下達到叢集平滑升級的效果。 在安全合規升級的過程中,系統應用的高可用性毫無疑問是放在第一優先順序的。 我們寧可升級的速度慢一點,也要保證叢集服務的正常執行。 在大資料如此多的應用中,資料儲存服務又是其中最為敏感的一部分。 因為這裡面涉及到的是海量規模的資料儲存,目前eBay大資料叢集儲存資料量遠遠超過PB,已經接近EB級別。 在這麼大體量的資料規模下,我們如何保證在不影響資料可用性的同時,又做到1個月內的平滑升級(資料儲存機器全部重啟升級一遍)。 本文將從HDFS儲存系統升級的挑戰、HDFS系統服務改進以及未來展望三方面來對此進行闡述。

HDFS儲存系統升級的挑戰

首先本文討論的儲存系統指的是HDFS(Hadoop Distribute File System)叢集,我們的升級過程會將HDFS裡的資料儲存節點上的DataNode服務進行停止並進行節點升級,然後再重新恢復DataNode服務。也就是說,那些處於升級過程中的節點是不提供資料服務能力的。從升級的過程我們能夠看到,升級對於儲存系統來說最大的一個挑戰是資料可用性的問題。對此我們理想達到的一個目標是在多節點因為升級導致DataNode服務停止期間,叢集資料服務不能受到絲毫影響。

瞭解過HDFS內部設計的同學可能覺得這不是一個大問題,因為HDFS本身實現了三副本的設計來保證資料可用性。假設1臺機器掛了,副本所在的另外2臺機器依然能提供資料的訪問能力。這難道不就解決了上面的問題了嗎?答案是否定的,它忽略了另外一個關鍵的影響因素:升級的速率。如果我們叢集升級的速率是按照逐個機器升級情況下的話,三副本設計當然能解決我們資料可用性的問題。但是逐臺機器升級的速率遠遠無法達到我們預期達到的1個月內升級萬臺以上機器的規模。所以我們實際升級速率是按照rack粒度的,每次升級停止的是一個rack上的DataNode服務。而停止一個rack數量的DataNode服務,對於叢集的影響就大很多了,因為HDFS三副本策略是將3副本分佈在2個rack上來實現rack awareness的。這時倘若一個rack上的2副本已經不能訪問了,這將大大增加block missing的風險。因為我們無法保證最後一臺副本所在的機器不會出現硬體故障或者壞盤的情況,從而導致資料無法訪問。

另外一個同樣是由停止整個rack服務引起的問題。當HDFS NameNode服務發現大量DataNode out of service狀態後,會對其上的副本進行重新replication操作,使其副本數重新達到期望副本數。這個過程會觸發上千萬的block replication數,我們如何避免這裡大量的replication對叢集造成的影響,這點也是另外一個需要考慮和解決的問題。

綜上兩點所述,HDFS儲存系統升級的挑戰有以下兩點:

1.資料可用性挑戰:在停止多DataNode服務下,如何保證資料可用性。

2.服務穩定性挑戰:在停止多DataNode服務後,如何保證系統服務穩定性。

接下來,我們來看一下我們是如何在HDFS系統層面來解決這兩個難題的。

HDFS系統服務改進

1.三副本多Rack部署

第一個是資料可用性的問題,剛剛上面已經介紹過,鑑於HDFS採用的是三副本分佈在2個rack的部署模式下,部署效果如下所示:

在以rack為升級操作粒度的情況下,這種部署方式會帶來極高丟資料的風險。那麼是否我們能夠通過改變上面副本部署方式來降低這種風險呢?繼續按照這個思路,是否我們能將副本分散在更多的rack上而不是僅僅儲存在2個rack裡面?

於是,我們初步設計瞭如下新的副本部署模式(placement)。

在有了這麼一個初步的新placement想法之後,我們繼續調研了與此相關的一些改動,這裡面主要有以下幾點:

1. 需要實現一個新的placement policy,支援placement可插拔式地使用

2. 新placement裡面對於excess block的處理

3. 新placement能夠進行fallback處理,假設當前叢集無法滿足此policy的條件時

4. Balancer工具能夠支援按placement policy的block搬遷

5. Decommission過程也同樣應當能夠支援按照placement policy的block replication

6. 新placement的block寫入效能監控

7. 新placement對於rack頻寬使用的影響

對於上面的幾點,由於本文篇幅有限,主要就新placement的實現邏輯做一個簡單的介紹。為了不更改預設placement的邏輯,我們繼承了BlockPlacementPolicyDefault類,override了其中chooseLocalRack方法,使其實際語義轉變為了選擇另外一個remote rack的效果,程式碼如下:

另外我們改寫了判斷選到的target是否是一個good candidate DataNode的邏輯,在裡面增加了rack數的判斷。但是如果是在choose target fallback條件下時,rack數的檢查會被跳過,這個時候整個選擇邏輯會變成隨機選擇location。

另外一部分與上面choose rack相關的必要改動是底層NetworkTopology類的改動。在目前NetworkTopology實現中,它只支援傳入一個exclude scope做location的選擇。但是在我們多rack placement下,我們需要傳入2個rack讓其exclude,以此才能準確選出第三個符合要求rack下的location。因此我們做了下面NetworkTopology#chooseRandom方法的擴充套件實現來支援新placement的實現:

在實現完上面新placement相關程式碼後,我們為了對其效能進行監控,另外加上了相關的細粒度metric,這樣能夠方便知道其block location選擇的效率,監控指標如下圖所示:

對於新placement的副本實際分佈效果,通過HDFS自帶的fsck命令就能看到其副本分佈模式。上線新placement到生產環境後,除了placement policy效率的問題之外,我們擔心的另外一點是它對於叢集頻寬的影響。因為相比較2個rack的模式,3個rack的資料寫pipeline會涉及到多一倍的跨rack間的流量。因此在實際上線後,我們也在密切關注著叢集內頻寬的實際使用情況,從目前觀察的情況來看,新placement並沒有造成頻寬的異常。

2.存量資料placement遷移

新placement是實現完成了,並且保證了新寫入的資料能夠按照三副本三rack的方式部署。但這裡還有一個更為棘手的問題需要解決,叢集裡那些規模龐大的存量資料依然採用的是兩rack的placement方式。我們還需要把所有存量資料做一遍placement的遷移轉換,這樣才算徹底地完成三副本多rack的部署。

在正式做block placement遷移之前,我們需要對待遷移block數做一個估算,以此確定採用哪種合適的方式來做這個遷移。待遷移的block數其實就是叢集當前總block數,將各個大小叢集block數相加,已經高達數十億規模量級。在如此大體量block數的情況下,placement遷移工作將會是一個逐漸遷移的過程,而不是一次性的快速遷移操作。再結合實際遷移場景的特點,通過工具命令的方式觸發遷移過程的執行是一種比較好的方案,這樣能夠保證整個遷移過程的可控性。

遷移計劃的大方向確定好之後,後面是如何來實現這樣一套專門做placement遷移的工具。首先,我們要關閉所有可能存在的HDFS自帶的placement檢查的邏輯,防止其內部檢查邏輯觸發大量的placement遷移。在這部分的檢查邏輯中,我們disable了NameNode啟動過程後的placement檢查和DataNode啟動後的block report的placement檢查。

上面提到的NameNode裡的placement檢查本質上是server端這邊的自動檢查行為,而我們的方案偏向於是一種外部client觸發的行為。我們總共設計了以下三種client-side的備選方案:

方案一:

利用現有Balancer工具的block balance行為。HDFS的Balancer工具是用來做資料塊的balance的,在資料balance過程中它在資料節點的選擇上已經能夠支援按照叢集設定的placement policy來選擇新的目標location(相關JIRA:HDFS-9007)。這點恰恰符合我們的遷移場景。

方案二:

基於Fsck path的block掃描檢查行為。HDFS的Fsck工具能夠按照給定path進行block的檢查,在檢查block的過程中同樣可以檢視資料的block placement。如果有發現哪個block placement不對的話,能夠觸發此block placement的遷移行為(相關JIRA:HDFS-14053)。此方案相當於是在namespace層做掃描來觸發底層storage的資料遷移,方案原理如下圖所示:

方案三:

按照node級別的block placement遷移。簡單來說就是我們再做一個類似於Balancer的工具,不過它能夠指定DataNode的block遷移。然後我們按照這種方式,逐個遷移完叢集中所有的節點。

綜合比較上面三套方案,方案一的缺點是其強依賴於資料balance行為,如果叢集本身已經達到資料均衡狀態,將不會有大量block被遷移。方案二Fsck方式的實際可操作性比較弱,它是一個one time的行為,一次觸發將會掃描指定路徑下的所有block,這將會在短時間內觸發大量的replication。方案三的缺點是需要額外開發一套能夠按照node級別的資料遷移工具,在做法上類似於Balancer工具目前的操作。綜合比較上述3個方案的優缺點,我們最終選擇了方案二Fsck的方式。

但是現有Fsck工具的可操作性還遠遠無法達到我們預期的要求,總結下來它還需要滿足以下幾點要求:

  • 能夠隨時中斷遷移過程,當發現遷移過程影響到了叢集正常服務的時候。

  • 能夠支援斷點繼續遷移,我們不希望每次從頭開始重複遷移已經完成的副本資料。

  • 能夠進行遷移速度的控制,這樣能夠靈活調整整體遷移的進度,不至於過快或過慢。

這裡解釋一下什麼叫做斷點繼續遷移,在實際placement遷移場景中,遷移過程是一個漫長的行為。這中間隨時可能因為NameNode重啟或者資料搬遷異常需要在某個時間點重新搬遷資料,那麼這時按理來說我們只需要從上次遷移成功的最後一個檔案開始遷移即可,而不是必須又得從頭開始遷移檔案。

隨後我們對Fsck工具進行了擴充套件改造,對於上面斷點繼續遷移的要求,我們在Fsck工具裡面做了一個startpath的功能來滿足這個要求。對於遷移速度的控制,我們讓Fsck block掃描操作按照指定batch size的方式進行掃描並且進行定期sleep等待,以此進行遷移速度的控制。另外我們增加了一個標記位開關能夠隨時中止正在執行的Fsck操作。整個Fsck的基本工作原理如下圖所示:

我們做的定製化改動主要集中在Fsck Tool本身以及部分NameNode裡的path掃描邏輯,因為最終觸發placement遷移的操作還是得由NameNode傳送指令讓DataNode來做。

下面是一個簡單使用樣例,我們輸入下面的fsck引數,指定startpath為/B,batch size為10000,sleep時間是1秒。

Sample command:

bin/hdfs fsck / -startpath /B -batch 10000 -sleep 1000

這個命令的意思是讓Fsck從/B目錄起,每次掃描、遷移10000個block,然後睡眠等待1秒,接著繼續下一批10000個block遷移,startpath的語義效果圖如下:

對於上面batch size掃描塊數量的確定,這個要取決於實際生產叢集replication的速度,我們參考了線上叢集處於忙碌狀態時7.5w block/分鐘的replication速度,設定了略小於此值的fsck掃描速率。最終我們利用這個新版本Fsck工具,花了2個多月時間成功地遷移了近20億個block,完成了叢集全部block placement的轉換。在三副本三rack部署模式下,叢集資料的可用性得到了很好的保證。

3.DataNode maintenance模式

在上面提到的困難挑戰中,還有一點是來自於升級過程造成的replication過多導致的潛在NameNode效能影響問題。但仔細來看這裡面的副本replication過程,其實它並不是必要的,理由如下:

1. 處於out of service狀態的DataNode是預期升級行為產生的,只是處於短暫服務停止狀態。等升級過程完成,DataNode將會重新恢復服務,此時又會導致NameNode去刪除之前replication出去的過量副本數的副本。

2. 目前我們採用的副本多rack部署模式能夠比較好地容忍單rack機器完全處於停服狀態的情況。

基於上述兩點理由,我們想要探索嘗試一種新的不會導致replication的新方案。後來我們參考了社群HDFS Maintenance State的原型(相關JIRA:HDFS-7877),在此基礎上進行了定製化的改動。

社群Maintenance State功能引入了一個新的名為Maintenance的狀態,並且支援Maintenance狀態和其它狀態的相互轉換。但是在我們的場景裡,我們只需要支援從In Service狀態到Maintenance狀態的互相轉換即可。因為這裡我們只會讓一個正在服務的DataNode置為Maintenance狀態,然後進行升級,升級完後再恢復成In Service狀態。

另外一個比較大的問題是社群版本功能實用性不好,目前社群Maintenance功能需要依賴外部檔案的修改來控制DataNode節點狀態變化,這在一定程度上增加了管理員對此的維護成本。鑑於我們生產叢集本身已經採用include/exclude host的方式管理DataNode機器,一旦要引入社群Maintenance功能,就必須得進行外部host內容的改造來支援此特性。這對於需要管理上萬臺機器的管理員來說,這無疑又增加了一定的維護成本。因此我們決定採用一種更加輕量級的做法,通過admin命令的方式來動態管理DataNode maintenance模式。樣例命令如下:

# 設定dn節點進入maintenance狀態,過期時間180秒(180秒後dn重新變成in service狀態)

$hdfs dfsadmin -maintenanceState -enter dn_hostname#180

# 設定dn節點離開maintenance狀態

$hdfs dfsadmin -maintenanceState -leave dn_hostname

上述命令列的方式本質上是在NameNode記憶體裡對DataNode狀態進行了更新,這裡面難免會有一個狀態資訊持久化的問題。一旦NameNode發生重啟或者failover,我們能保證裡面狀態的一致性嗎?目前我們只做到了保證failover的行為是能夠達到狀態一致的,這樣保證了至少有一個NameNode能夠擁有正確的DataNode狀態。至於重啟丟掉狀態資訊的NameNode,需要再次執行admin命令來恢復DataNode maintenance狀態資訊。這麼做的原因前面已經提過,是出於實際功能維護成本的考慮,沒有做到完全持久化處理。本身maintenance window往往是比較短的一個時間區間。

綜上所述,經過我們定製化改造的DataNode maintenance模式的狀態機轉換如下圖所示,總共有4個狀態:

經過上述HDFS系統層面的改進後,我們將maintenance模式結合三副本多rack部署完美地應用到了我們的升級場景裡面,升級過程大致如下圖所示:

在叢集升級開始前,我們會通過Delos系統(eBay Hadoop大資料叢集運維平臺)將待升級rack裡的DataNode全部置成maintenance模式。然後有另外的系統對maintenance的rack進行升級,對於處在maintenance機器上的資料,使用者是無法訪問的,此時要依託於其它rack上的副本來提供資料的訪問。

未來展望

對於未來的展望,我們希望繼續提升當前叢集資料的高可用性,以此能夠做到在更加極端條件下的資料服務能力。在未來我們計劃能夠做到叢集資料跨rack同時跨區域的部署(一個叢集部署在少數幾個域內,每個域之間相互獨立)。這樣我們能夠做到在一個域內所有機器都不可用的情況下時,使用者的資料訪問依然不會受到影響。

參考:

1.https://issues.apache.org/jira/browse/HDFS-7877

2.https://issues.apache.org/jira/browse/HDFS-9007

3.https://issues.apache.org/jira/browse/HDFS-14053

往期推薦

eBay大資料安全合規系列 - 系統篇

Elasticsearch叢集容量的自適應管理

“億”義非凡|eBay2023校園招聘提前批正式開啟

點選 “閱讀原文” ,  一鍵投遞

eBay大量優質職位虛席以待

我們的身邊,還缺一個你