叢儲俊,張偉
(上海威士頓信息技術(shù)股份有限公司,上海 200052)
Hadoop集群以其開源、廉價、易拓展、社區(qū)資源豐富等特點,近年來成為大數(shù)據(jù)存儲與分析方面最受歡迎的平臺。不論是傳統(tǒng)行業(yè)、金融業(yè)還是互聯(lián)網(wǎng)行業(yè)都青睞于將傳統(tǒng)數(shù)據(jù)倉庫遷移至Hadoop的分布式存儲系統(tǒng)中。
HBase是一個基于Java、開源、NoSQL、非關(guān)系型、面向列的、構(gòu)建于Hadoop分布式文件系統(tǒng)( HDFS )上的、仿照谷歌的BigTable的論文開發(fā)的分布式數(shù)據(jù)庫。
HBase是要建立一個可容錯并托管一些大的數(shù)據(jù)稀疏表(億元/兆行數(shù)以百萬計列 )的應(yīng)用,同時允許非常低的延遲和近實時的隨機讀取和隨機寫入。
HBase的設(shè)計保證了“以一致性為前提的可用性”,并且由于能夠快速自動完成故障轉(zhuǎn)移,因此也具有高可用性。
HBase將數(shù)據(jù)存儲在表(table)中,一個HBase表由一個或者多個列簇(CF,column family)組成,一個列簇又包含很多列(稱為列限定符,簡稱“CQ”,column qualifier ),每列存儲相應(yīng)的值。一行由很多列組成,全部由相同的行鍵(rowkey)引用。一個特定的列和一個行鍵稱為單元格(cell)。一個單元格可以有很多版本,由不同時間戳的版本來區(qū)分。HBase會根據(jù)字節(jié)值將行鍵進行排序[1]。
物理上,一個表由一個或者多個region組成,一個region由一個或者多個列簇組成,一個列簇由一個store組成,一個store由唯一的MemStore(HBase 2.x以后支持多個MemStore)加上一個或者多個HFile組成,HFile又是由 block組成的,而block是由cell組成的。
所有的行以及相關(guān)的列一起形成了一張表。但是,為了提供可擴展以及快速隨機訪問的功能,HBase不得不將數(shù)據(jù)分布在多個服務(wù)器中。為了達到這個目的,表被分割成多個region存儲,每個region將會存儲一個指定區(qū)間的數(shù)據(jù)。region將會被分配到Region Server上,Region Server提供對于每個region的內(nèi)容訪問服務(wù)。當新的region被創(chuàng)建后,過了配置的一段時間后,HBase的負載平衡器將會把region移動到其他的Region Server上,以確保HBase集群負載均衡。
每個region都有一個起始鍵和一個結(jié)束鍵來定義它的邊界,稱之為rowkey范圍。所有這些信息將隨著文件保存在region中,也會保存在hbase:meta表中(對于HBase 0.96之前的版本則保存在 .META. 中)。通過這張表能夠跟蹤所有的 region信息。當region變得太大后,region可以自動分裂或者手動。如果需要,region也可以合并[2]。
正常情況下,一張表的任意兩個region的起始鍵和結(jié)束鍵的范圍是彼此不重疊的,這樣的region可以提供正確的讀寫服務(wù),如果由于某些原因?qū)е掠兄丿B的(overlap)region出現(xiàn),則受影響范圍內(nèi)的行鍵對應(yīng)的數(shù)據(jù)是不能夠讀寫的。
本文就HBase Region Overlap的相關(guān)問題進行分析,并提出一種通過代碼進行修復(fù)的方式。
HBase的讀寫流程比較復(fù)雜,有很長的調(diào)用鏈,本文只對可能導(dǎo)致region overlap問題出現(xiàn)的步驟以及受region overlap問題影響的步驟進行分析。
HBase寫入流程可以概括為三個階段。
(1)客戶端處理階段:客戶端將用戶的寫入請求進行預(yù)處理,并根據(jù)集群元數(shù)據(jù)定位即將寫入數(shù)據(jù)的region所在的RegionServer,然后將請求發(fā)送給對應(yīng)的RegionServer。
(2)Region寫入階段:Region Server接收到寫入請求之后將數(shù)據(jù)解析出來,首先寫入WAL(Write-Ahead Log,HBase的實現(xiàn)是HLog),再寫入對應(yīng)Region列簇的Mem Store。
(3)M em Stor e Fl u sh階段:當Region中Mem Stor e容量超過一定閾值時,系統(tǒng)會異步執(zhí)行f lush操作,將內(nèi)存中的數(shù)據(jù)寫入文件,形成HFile。
在HBase寫入過程中,會首先從Zookeeper那里獲得元數(shù)據(jù)hbase:meta表所在的Region Server,通過查詢hbase:meta表獲得所寫數(shù)據(jù)表的region的row key范圍定義以及每個region所在的region server,然后根據(jù)代寫的每一條記錄的row key和對應(yīng)的region server聯(lián)系并寫入數(shù)據(jù)。如果region的row key范圍發(fā)生重疊,也就是發(fā)生了region overlap問題,則一條記錄可能會對應(yīng)一個以上的region,無法確定應(yīng)該寫入哪個region,就導(dǎo)致了數(shù)據(jù)寫入失敗[3]。
HBase的讀取流程更加復(fù)雜,分為get和scan兩大類,這里只描述根據(jù)rowkey獲得數(shù)據(jù)的get方式,這種方式受region overlap 問題的影響比較大。讀取數(shù)據(jù)的時候,首先會從ZooKeeper中獲取元數(shù)據(jù)hbase:meta表所在的Region Server,然后獲得待讀取數(shù)據(jù)表的region的元數(shù)據(jù),包括各個region的row key范圍以及所在的Region Server,最后根據(jù)row key將讀取請求發(fā)送到對應(yīng)的Region Server進行處理。和寫入數(shù)據(jù)類似,如果region的row key范圍發(fā)生了重疊,也就是發(fā)生了region overlap問題,就無法確定應(yīng)該和哪個RegionServer聯(lián)系,就導(dǎo)致了數(shù)據(jù)讀取失敗。
Region分裂是H Base最核心的功能之一,是H Base實現(xiàn)分布式可擴展性的基礎(chǔ),類似傳統(tǒng)的My SQL的分庫分表,只不過這一過程是自動的而且分裂的依據(jù)固定為row key。概括來說,當數(shù)據(jù)表的一個region的一個列簇的大小超過一定的閾值就會發(fā)生水平分裂,分裂為兩個region。假設(shè)原region的row key范圍為[start,end),則分裂后的兩個region的范圍分別為[start1,end1)和[start2,end2),其中start1=start,end2=end,end1=start2。
Region分裂有多種觸發(fā)策略可以配置,一旦觸發(fā),HBase會自動尋找分裂點,就是end 1和start2,然后執(zhí)行真正的分裂操作。目前HBase有多重分裂觸發(fā)策略,這些策略與region overlap問題關(guān)系不大,所以這里不詳細分析了。
HBase將r egion的分裂過程設(shè)計為一個完整的事務(wù),希望整個分裂過程分為三個階段:準備(prepare)、執(zhí)行(execute)和回滾(rollback)。
Region分裂是個比較復(fù)雜的過程,涉及父Region中HFile文件分裂、兩個子Region生成、系統(tǒng)meta元數(shù)據(jù)更改等很多子步驟,因此必須保證整個分裂過程的原子性,即要么分裂成功,要么分裂失敗,在任何情況下不能出現(xiàn)分裂完成一半的情況。
正常的分裂結(jié)果如圖1所示
不正常的分裂結(jié)果如圖2所示
HBase是一個健壯的分布式系統(tǒng),但是在實際生產(chǎn)過程中由于硬件故障、操作系統(tǒng)故障等原因,偶爾還是會出現(xiàn)莫名的崩潰,導(dǎo)致hbase:meta報告兩個不同的region卻有相同的或者重合的start key和end key。還有一種情況是運維人員或者某些工具軟件跳過HBase直接操作HBase保存在HDFS上的文件或者目錄,導(dǎo)致HBase的數(shù)據(jù)和元數(shù)據(jù)不匹配。還有一種典型的場景是在HBase 2.0上使用了hbase hbck進行強行修復(fù),這也可能導(dǎo)致region overlap問題。在HBase 2.0之前,hbck提供了修復(fù)overlap的功能,但是在HBase 2.0之后,由于采用了新的分布式事務(wù)框架Procedure V2(HBASE-12439),原有的修復(fù)邏輯不能使用,而符合Procedure V2的修復(fù)功能目前還沒有完成,所以強行使用hbck修復(fù),結(jié)果是不可預(yù)期的[4]。
可以通過region的合并功能將有overlap問題的相鄰的兩個region進行合并,產(chǎn)生一個較大的region,這個region包含了原有的兩個region的所有數(shù)據(jù)。
當只有少數(shù)的region overlap時,可以通過hbase shell進行手工合并,但是實際上由于硬件故障、操作系統(tǒng)故障、不小心的底層操作(比如直接操作HDFS文件)等原因,可能會出現(xiàn)大量的region overlap,這時候采用手工合并將耗費大量時間而且容易出錯,所以需要基于這一思路采用編程的方式自動地實現(xiàn)這一合并過程。
為了方便測試,首先需要一個能夠比較快速重現(xiàn)region over問題的方式,這個可以通過shell腳本來實現(xiàn)。
空表的重現(xiàn)步驟是:
(1)創(chuàng)建一個預(yù)分區(qū)的表,比如create 't1','cf1', { NUMREGIONS => 100, SPLITALGO => 'HexStringSplit' },這會在HDFS上建立對應(yīng)的目錄結(jié)構(gòu)。
(2)在HDFS上建立一個臨時目錄,然后把上述步驟建立的HBase表在HDFS上的全部內(nèi)容移動到這個臨時目錄。
(3)Disable刪除剛剛創(chuàng)建的HBase表,然后以同樣的名字創(chuàng)建預(yù)分區(qū)表,但是分區(qū)的數(shù)量與第一次不同,比如create 't3','cf1', { NUMREGIONS => 70, SPLITALGO => 'HexStringSplit' }
(4)把之前臨時目錄的內(nèi)容移動到新建表的目錄下。
(5)運行hbase hbck,會報告有region目錄信息存在于HDFS,但是沒有存在于hbase:meta,這是預(yù)期的結(jié)果。
(6)通過hbck2 的addFsRegionsMissingInMeta功能將HDFS上的region信息寫入hbase:meta。
(7)再次運行hbase hbck,會報告大量的region overlap問題。
進一步測試需要有大量數(shù)據(jù)的場景,重現(xiàn)步驟跟無數(shù)據(jù)的過程類似,只是建表的語句用hbase ltt -write代替,比如hbase ltt -write 30:20:10 -num_keys 10000 -num_regions_per_server 3建表后會在每個RegionServer上創(chuàng)建3個分區(qū),然后用10個線程寫入10000條記錄,每條記錄30列,每個cell的大小是20個字節(jié),這樣的場景更接近于真實環(huán)境。
region的信息保存在hbase:meta表中,可以通過org.apache.hadoop.hbase.client.Admin接口的getRegions獲得一個列表,這個列表是按rowkey字典順序排序的,通過兩兩比較相鄰的region的start和end來判斷是否發(fā)生了overlap。
假設(shè)相鄰的region的rowkey范圍分別是[startKey1,endKey1)和[startKey2,endKey2),則有如下幾種overlap的情況:RegionInfo>> regionInfos。
總的思路是將查找到的有問題的每對region進行合并。兩個region合并會產(chǎn)生第三個region,同時原有的兩個region會被下線并從hbase:meta中刪除,然后將新生成的region上線,整個過程是個異步過程,所以發(fā)出合并指令到最終完成需要一定的時間,這期間新的region即使和后面的region還是有overlap,也不能進行合并,強行進行合并會導(dǎo)致報錯,所以需要加以判斷,這個判斷可以通過查詢hbase:meta表獲得必要的信息,通過查詢列簇HConstants.CATALOG_FAMILY里名為“merge”的一列可以獲得必要的數(shù)據(jù)。具體實現(xiàn)可以參考hbase-operator-tools的子項目Apache HBase HBCK2 Tool中的HBCKMetaTableAccessor代碼[5]。
當HBase在拆分或者合并的時候,為了確保數(shù)據(jù)不丟失,都會保留原來的region,在拆分或者合并過程結(jié)束后再等待目錄管理器來清理這些舊的region信息。在反復(fù)合并的過程中較短時間內(nèi)會有大量的舊的region信息,需要開啟HBase的臨時開啟CatalogJanitor功能,可以考慮先記錄目前系統(tǒng)內(nèi)的CatalogJanitor功能的狀態(tài),在修復(fù)完成后恢復(fù)這個狀態(tài)。
HBase是目前大數(shù)據(jù)技術(shù)棧的主要組件,主要承擔數(shù)據(jù)的隨機讀寫任務(wù)。HBase region是HBase用來實現(xiàn)負載均衡和可擴展性的重要概念。在HBase運行過程中,HBase 會自動執(zhí)行region分裂、合并、上下線等操作,或者HBase的運維人員也會手動地進行這些操作。在操作的過程中,由于軟硬件的故障,會導(dǎo)致region的rowkey的排布出現(xiàn)互相重疊的問題,導(dǎo)致讀寫HBase數(shù)據(jù)出現(xiàn)問題,這就是HBase Region Overlap問題。本文分析了產(chǎn)生問題的原因,并描述了重現(xiàn)問題、檢測問題和解決問題的邏輯,對于保證HBase長期穩(wěn)定的運行有比較大的幫助。未來會進一步完善處理邏輯,將其作為一個組件加入hbase hbck2 tools中。