深入解讀HBase2.0新功能之高可用讀Region Replica

深入解讀HBase2.0新功能之高可用讀Region Replica

來自專欄我是程序員7 人贊了文章

摘要:AssignmentManager是HBase中一個非常重要的模塊,負責Region在server上的狀態變化,如Open、Close這些操作。HBase2.0中對AssignmentMananger做了重大重構,這邊文章主要分析了之前AssignmentManager的問題,以及HBase2.

背景

AssignmentManager模塊是HBase中一個非常重要的模塊,Assignment Manager(之後簡稱AM)負責了HBase中所有region的Assign,UnAssign,以及split/merge過程中region狀態變化的管理等等。在HBase-0.90之前,AM的狀態全部存在內存中,自從HBASE-2485之後,AM把狀態持久化到了Zookeeper上。在此基礎上,社區對AM又修復了大量的bug和優化(見此文章),最終形成了用在HBase-1.x版本上的這個AM。

老Assignment Mananger的問題

相信深度使用過HBase的人一般都會被Region RIT的狀態困擾過,長時間的region in transition狀態簡直令人抓狂。

除了一些確實是由於Region無法被RegionServer open的case,大部分的RIT,都是AM本身的問題引起的。總結一下HBase-1.x版本中AM的問題,主要有以下幾點:

region狀態變化複雜

這張圖很好地展示了region在open過程中參與的組件和狀態變化。可以看到,多達7個組件會參與region狀態的變化。並且在region open的過程中多達20多個步驟!越複雜的邏輯意味著越容易出bug

region狀態多處緩存

region的狀態會緩存在多個地方,Master中RegionStates會保存Region的狀態,Meta表中會保存region的狀態,Zookeeper上也會保存region的狀態,要保持這三者完全同步是一件很困難的事情。同時,Master和RegionServer都會修改Meta表的狀態和Zookeeper的狀態,非常容易導致狀態的混亂。如果出現不一致,到底以哪裡的狀態為準?每一個region的transition流程都是各自為政,各自有各自的處理方法

重度依賴Zookeeper

在老的AM中,region狀態的通知完全通過Zookeeper。比如說RegionServer打開了一個region,它會在Zookeeper把這個region的RIT節點改成OPEN狀態,而不去直接通知Master。Master會在Zookeeper上watch這個RIT節點,通過Zookeeper的通知機制來通知Master這個region已經發生變化。Master再根據Zookeeper上讀取出來的新狀態進行一定的操作。嚴重依賴Zookeeper的通知機制導致了region的上線/下線的速度存在了一定的瓶頸。特別是在region比較多的時候,Zookeeper的通知會出現嚴重的滯後現象。

正是這些問題的存在,導致AM的問題頻發。我本人就fix過多個AM導致region無法open的issue。比如說這三個相互關聯的「連環」case:HBASE-17264,HBASE-17265,HBASE-17275。

Assignment Mananger V2

面對這些問題的存在,社區也在不斷嘗試解決這些問題,特別是當region的規模達到100w級別的時候,AM成為了一個嚴重的瓶頸。HBASE-11059中提出的ZK-less Region Assignment就是一個非常好的改良設計。在這個設計中,AM完全擺脫了Zookeeper的限制,在測試中,zk-less的assign比zk的assign快了一個數量級!

但是在這個設計中,它摒棄了Zookeeper這個持久化的存儲,一些region transition過程中的中間狀態無法被保存。因此,在此基礎上,社區又更進了一步,提出了Assignment Mananger V2在這個方案。在這個方案中,仍然摒棄了Zookeeper參與Assignment的整個過程。但是,它引入了ProcedureV2這個持久化存儲來保存Region transition中的各個狀態,保證在master重啟時,之前的assing/unassign,split等任務能夠從中斷點重新執行。具體的來說,AMv2方案中,主要的改進有以下幾點:

Procedure V2

關於Procedure V2,我之後將獨立寫文章介紹。這裡,我只大概介紹下ProcedureV2和引入它所帶來的價值。

我們知道,Master中會有許多複雜的管理工作,比如說建表,region的transition。這些工作往往涉及到非常多的步驟,如果master在做中間某個步驟的時候宕機了,這個任務就會永遠停留在了中間狀態(RIT因為之前有Zookeeper做持久化因此會繼續從某個狀態開始執行)。比如說在enable/disable table時,如果master宕機了,可能表就停留在了enabling/disabling狀態。需要一些外部的手段進行恢復。那麼從本質上來說,ProcedureV2提供了一個持久化的手段(通過ProcedureWAL,一種類似RegionServer中WAL的日誌持久化到HDFS上),使master在宕機後能夠繼續之前未完成的任務繼續完成。同時,ProcedureV2提供了非常豐富的狀態轉換並支持回滾執行,即使執行到某一個步驟出錯,master也可以按照用戶的邏輯對之前的步驟進行回滾。比如建表到某一個步驟失敗了,而之前已經在HDFS中創建了一些新region的文件夾,那麼ProcedureV2在rollback的時候,可以把這些殘留刪除掉。

Procedure中提供了兩種Procedure框架,順序執行和狀態機,同時支持在執行過程中插入subProcedure,從而能夠支持非常豐富的執行流程。在AMv2中,所有的Assign,UnAssign,TableCreate等等流程,都是基於Procedure實現的。

去除Zookeeper依賴

有了Procedure V2之後,所有的狀態都可以持久化在Procedure中,Procedure中每次的狀態變化,都能夠持久化到ProcedureWAL中,因此數據不會丟失,宕機後也能恢復。同時,AMv2中region的狀態扭轉(OPENING,OPEN,CLOSING,CLOSE等)都會由Master記錄在Meta表中,不需要Zookeeper做持久化。再者,之前的AM使用的Zookeeper watch機制通知master region狀態的改變,而現在每當RegionServer Open或者close一個region後,都會直接發送RPC給master彙報,因此也不需要Zookeeper來做狀態的通知。綜合以上原因,Zookeeper已經在AMv2中沒有了存在的必要。

減少狀態衝突的可能性

之前我說過,在之前的AM中,region的狀態會同時存在於meta表,Zookeeper和master的內存狀態。同時Master和regionserver都會去修改Zookeeper和meta表,維護狀態統一的代價非常高,非常容易出bug。而在AMv2中,只有master才能去修改meta表。並在region整個transition中做為一個「權威」存在,如果regionserver彙報上來的region狀態與master看到的不一致,則master會命令RegionServer abort。Region的狀態,都以master內存中保存的RegionStates為準。

除了上述這些優化,AMv2中還有許多其他的優化。比如說AMv2依賴Procedure V2提供的一套locking機制,保證了對於一個實體,如一張表,一個region或者一個RegionServer同一時刻只有一個Procedure在執行。同時,在需要往RegionServer發送命令,如發送open,close等命令時,AMv2實現了一個RemoteProcedureDispatcher來對這些請求做batch,批量把對應伺服器的指令一起發送等等。在代碼結構上,之前處理相應region狀態的代碼散落在AssignmentManager這個類的各個地方,而在AMv2中,每個對應的操作,都有對應的Procedure實現,如AssignProcedure,DisableTableProcedure,SplitTableRegionProcedure等等。這樣下來,使AssignmentManager這個之前雜亂的類變的清晰簡單,代碼量從之前的4000多行減到了2000行左右。

AssignProcedure

AMv2中有太多的Procedure對應各種不同的transition,這裡不去詳細介紹每個Procedure的操作。我將以AssignProcedure為例,講解一下在AMv2中,一個region是怎麼assign給一個RegionServer,並在對應的RS上Open的。

AssignProcedure是一個基於Procedure實現的狀態機。它擁有3個狀態:

  • REGION_TRANSITION_QUEUE: Assign開始時的狀態。在這個狀態時,Procedure會對region狀態做一些改變和存儲,並丟到AssignmentManager的assign queue中。對於單獨region的assign,AssignmentManager會把他們group起來,再通過LoadBalancer分配相應的伺服器。當這一步驟完成後,Procedure會把自己標為REGION_TRANSITION_DISPATCH,然後看是否已經分配伺服器,如果還沒有被分配伺服器的話,則會停止繼續執行,等待被喚醒。
  • REGION_TRANSITION_DISPATCH: 當AssignmentManager為這個region分配好伺服器時,Procedure就會被喚醒。或者Procedure在執行完REGION_TRANSITION_QUEUE狀態時master宕機,Procedure被恢復後,也會進入此步驟執行。所以在此步驟下,Procedure會先檢查一下是否分配好了伺服器,如果沒有,則把狀態轉移回REGION_TRANSITION_QUEUE,否則的話,則把這個region交給RemoteProcedureDispatcher,發送RPC給對應的RegionServer來open這個region。同樣的,RemoteProcedureDispatcher也會對相應的指令做一個batch,批量把一批region open的命令發送給某一台伺服器。當命令發送完成之後,Procedure又會進入休眠狀態,等待RegionServer成功OPen這個region後,喚醒這個Procedure
  • REGION_TRANSITION_FINISH: 當有RegionServer彙報了此region被打開後,會把Procedure的狀態置為此狀態,並喚醒Procedure執行。此時,AssignProcedure會做一些狀態改變的工作,並修改meta表,把meta表中這個region的位置指向對應的RegionServer。至此,region assign的工作全部完成。

AMv2中提供了一個Web頁面(Master頁面中的『Procedures&Locks』鏈接)來展示當前正在執行的Procedure和持有的鎖。

其實通過log,我們也可以看到Assign的整個過程。

假設,一台server宕機,此時master會產生一個ServerCrashProcedure 來處理,在這個Procedure中,會做一系列的工作,比如WAL的restore。當這些前置的工作做完後,就會開始assign之前在宕掉伺服器上的region,比如56f985a727afe80a184dac75fbf6860c。此時會在ServerCrashProcedure產生一系列的子任務:

2017-05-23 12:04:24,175 INFO [ProcExecWrkr-30] procedure2.ProcedureExecutor: Initialized subprocedures=[{pid=1178, ppid=1176, state=RUNNABLE:REGION_TRANSITION_QUEUE; AssignProcedure table=IntegrationTestBigLinkedList, region=bfd57f0b72fd3ca77e9d3c5e3ae48d76, target=ve0540.halxg.cloudera.com,16020,1495525111232}, {pid=1179, ppid=1176, state=RUNNABLE:REGION_TRANSITION_QUEUE; AssignProcedure table=IntegrationTestBigLinkedList, region=56f985a727afe80a184dac75fbf6860c, target=ve0540.halxg.cloudera.com,16020,1495525111232}]

可以看到,ServerCrashProcedure的pid(Procedure ID)為1178,在此Procedure中產生的assign 56f985a727afe80a184dac75fbf6860c這個region的子Procedure的pid為1179,同時他的ppid(Parent Procedure ID)為1178。在AMv2中,通過追蹤這些ID,就非常容易把一個region的transition整個過程全部串起來。

接下來,pid=1170這個Procedure開始執行,首先執行的是REGION_TRANSITION_QUEUE狀態的邏輯,然後進入睡眠狀態。

2017-05-23 12:04:24,241 INFO [ProcExecWrkr-30] assignment.AssignProcedure: Start pid=1179, ppid=1176, state=RUNNABLE:REGION_TRANSITION_QUEUE; AssignProcedure table=IntegrationTestBigLinkedList, region=56f985a727afe80a184dac75fbf6860c, target=ve0540.halxg.cloudera.com,16020,1495525111232; rit=OFFLINE, location=ve0540.halxg.cloudera.com,16020,1495525111232; forceNewPlan=false, retain=false

當target server被指定時,Procedure進入REGION_TRANSITION_DISPATCH狀態,dispatch了region open的請求,同時把meta表中region的狀態改成了OPENING,然後再次進入休眠狀態

2017-05-23 12:04:24,494 INFO [ProcExecWrkr-38] assignment.RegionStateStore: pid=1179 updating hbase:meta row=IntegrationTestBigLinkedList,HxE3@x8Dx964x9DxDFx8F@9x0FxC8xCCxC2,1495566261066.56f985a727afe80a184dac75fbf6860c., regionState=OPENING, regionLocation=ve0540.halxg.cloudera.com,16020,1495525111232 2017-05-23 12:04:24,498 INFO [ProcExecWrkr-38] assignment.RegionTransitionProcedure: Dispatch pid=1179, ppid=1176, state=RUNNABLE:REGION_TRANSITION_DISPATCH; AssignProcedure table=IntegrationTestBigLinkedList, region=56f985a727afe80a184dac75fbf6860c, target=ve0540.halxg.cloudera.com,16020,1495525111232; rit=OPENING, location=ve0540.halxg.cloudera.com,16020,1495525111232

最後,當RegionServer打開了這個region後,會發RPC通知master,那麼在通知過程中,這個Procedure再次被喚醒,開始執行REGION_TRANSITION_FINISH的邏輯,最後更新meta表,把這個region置為打開狀態。

2017-05-23 12:04:26,643 DEBUG [RpcServer.default.FPBQ.Fifo.handler=46,queue=1,port=16000] assignment.RegionTransitionProcedure: Received report OPENED seqId=11984985, pid=1179, ppid=1176, state=RUNNABLE:REGION_TRANSITION_DISPATCH; AssignProcedure table=IntegrationTestBigLinkedList, region=56f985a727afe80a184dac75fbf6860c, target=ve0540.halxg.cloudera.com,16020,1495525111232; rit=OPENING, location=ve0540.halxg.cloudera.com,16020,1495525111232 2017-05-23 12:04:26,643 INFO [ProcExecWrkr-9] assignment.RegionStateStore: pid=1179 updating hbase:meta row=IntegrationTestBigLinkedList,HxE3@x8Dx964x9DxDFx8F@9x0FxC8xCCxC2,1495566261066.56f985a727afe80a184dac75fbf6860c., regionState=OPEN, openSeqNum=11984985, regionLocation=ve0540.halxg.cloudera.com,16020,14955251112322017-05-23 12:04:26,836 INFO [ProcExecWrkr-9] procedure2.ProcedureExecutor: Finish suprocedure pid=1179, ppid=1176, state=SUCCESS; AssignProcedure table=IntegrationTestBigLinkedList, region=56f985a727afe80a184dac75fbf6860c, target=ve0540.halxg.cloudera.com,16020,1495525111232

一路看下來,由於整個region assign的過程都是在Procedure中執行,整個過程清晰明了,非常容易追述,也沒有了Zookeeper一些event事件的干擾。

總結

Assignment Mananger V2依賴Procedure V2實現了一套清晰明了的region transition機制。去除了Zookeeper依賴,減少了region狀態衝突的可能性。整體上來看,代碼的可讀性更強,出了問題也更好查錯。對於解決之前AM中的一系列「頑疾」,AMv2做了很好的嘗試,也是一個非常好的方向。

AMv2之所以能保持簡潔高效的一個重要原因就是重度依賴了Procedure V2,把一些複雜的邏輯都轉移到了Procedure V2中。但是這樣做的問題是:一旦ProcedureWAL出現了損壞,或者Procedure本身存在bug,這個後果就是災難性的。事實上在我們的測試環境中,就出現過PRocedureWAL損壞導致region RIT的情況。

另外需要注意的是,截止目前為止,HBCK仍然無法支持AMv2,這會導致一旦出現問題,修復起來會比較困難。

當然,新的事務還是要有一段成熟期,相信經過一段時間的bug修復和完善後,我相信AMv2一定會完美解決之前的一些問題,給HBase的運維上帶來一些不同的體驗。願世界不再被HBase的RIT困擾 :-)。

雲端使用

阿里HBase目前已經在阿里雲提供商業化服務,任何有需求的用戶都可以在阿里雲端使用深入改進的、一站式的HBase服務。雲HBase版本與自建HBase相比在運維、可靠性、性能、穩定性、安全、成本等方面均有很多的改進,更多內容歡迎大家關注 aliyun.com/product/hbas

同時,雲HBase2.0 在2018年6月6日正式發布,點擊了解更多: promotion.aliyun.com/nt

本文作者:正研

原文鏈接

更多技術乾貨敬請關注云棲社區知乎機構號:阿里云云棲社區 - 知乎

本文為雲棲社區原創內容,未經允許不得轉載。

推薦閱讀:

N維圖像的數據增強方法概覽
水晶手鏈穿繩打結的方法>中國結>手工製作|科技小製作|小發明小製作|廢物利用|發明專利|幼...
英偉達踩上壟斷爭議線的合作夥伴計劃告終,博客訴苦市場誤解善意
2016年世界國防科技管理改革綜述

TAG:計算機科學 | 科技 |