作者: 大圓那些事 | 文章可以轉載,請以超鏈接形式標明文章原始出處和作者信息
HBase集群在讀寫過程中,可能由於Region Split或Region Blance等導致Region的短暫下線,此時客戶端與HBase集群進行RPC操作時會拋出NotServingRegionException異常,從而導致讀寫操作失敗。這里根據實際項目經驗,詳細描述這一問題的發現及排查解決過程。
1. 發現問題
在對HBase集群進行壓力測試過程中發現,當實際寫入HBase和從HBase查詢的量是平時的若干倍時(集群規模10~20台,每秒讀寫數據量在幾十萬條記錄的量級),導致集群的讀寫出現一定程度的波動。具體如下:
1)寫端拋出以下異常信息:
org.apache.hadoop.hbase.client.RetriesExhaustedWithDetailsException: Failed 150 actions: NotServingRegionException: 150 times, servers with issues: my161208.cm6:60020, at org.apache.hadoop.hbase.client.HConnectionManager$HConnectionImplementation.processBatchCallback(HConnectionManager.java:1600) at org.apache.hadoop.hbase.client.HConnectionManager$HConnectionImplementation.processBatch(HConnectionManager.java:1376) at org.apache.hadoop.hbase.client.HTable.flushCommits(HTable.java:916) |
2)讀端也拋出類似異常信息:
org.apache.hadoop.hbase.client.RetriesExhaustedException: Failed after attempts=10, exceptions: Mon Oct 29 14:03:09 CST 2012, org.apache.hadoop.hbase.client.ScannerCallable@3740fb20, org.apache.hadoop.hbase.NotServingRegionException: org.apache.hadoop.hbase.NotServingRegionException: xxxxxx,\x0FP\x8D\xC3\xDB1053223266:\x00\x00V6,1351490475989.bd68113129f07163dc25e78fba17ad6c. is closing |
以上異常,在壓測期間周期性地出現,HBase集群由此出現了短暫的不可服務期。
2. 排查問題
通過查看HBase Master運行日志,結合客戶端拋出異常的時刻,發現當時HBase集群內正在進行Region的Split和不同機器之間的Region Balance,那么,為什么會周期性頻繁觸發以上過程呢?而且是發生在壓測期間(數據量與平時相比大幾倍)。下面結合表的設計來分析一下:
1)由於表中rowkey有時間字段,因此每天都需要新創建Region,同時由於寫入數據量大,進一步觸發了HBase的Region Split操作,這一過程一般耗時較長(測試時從線上日志來看,平均為10秒左右,Region大小為4GB),且Region Split操作觸發較為頻繁;
2)同時由於Region Split操作導致Region分布不均勻,進而觸發HBase自動做Region Balance操作,Region遷移過程中也會導致Region下線,這一過程耗時較長(測試時從線上日志來看,平均為20秒左右)。
3. 解決問題
首先,從客戶端考慮,其實就是要保證Region下線不可服務期間,讀寫請求能夠在集群恢復后繼續,具體可以采取如下措施:
1)對於寫端,可以將未寫入成功的記錄,添加到一個客戶端緩存中,隔一段時間后交給一個后台線程統一重新提交一次;也可以通過setAutoFlush(flase, false)保證提交失敗的記錄不被拋棄,留在客戶端writeBuffer中等待下次writeBuffer滿了后再次嘗試提交,直到提交成功為止。
2)對於讀端,捕獲異常后,可以采取休眠一段時間后進行重試等方式。
3)當然,還可以根據實際情況合理調整hbase.client.retries.number和hbase.client.pause配置選項。
然后,從服務端考慮,需要分別針對Region Split和Region Balance進行解決:
1)由於建表時,我們已經考慮到了數據在不同Region Server上的均勻分布,而且預先在不同Region Server上創建並分配了相同數目的Region,那么考慮到為了集群能夠在實際線上環境下提供穩定的服務,可以選擇關掉HBase的Region自動Balance功能,當然關掉后可以選擇在每天讀寫壓力小的時候(如凌晨后)觸發執行一次Balance操作即可。
2)接下來,Region總是被創建,不能被復用的問題該如何解決呢?根本原因是rowkey中包含了timestamp字段,而每時每刻timestamp總是向上增長的。但是,使用方確實需要能夠根據timestamp字段進行順序scan操作,因此,timestamp字段必須保留。據此,這里給出兩種解決思路:
- 一種常用方法是將表按照時間分表,例如按天進行分表,這樣可以通過預先建表創建好Region分區,避免實際讀寫過程中頻繁觸發Region Split等過程,但是這一方法的缺點是每天需要預先建好表,而這一DDL過程可能出現問題進而導致讀寫出現問題,同時跨天時讀寫端也需要做出適應,調整為讀寫新創建的表。
- 其實,我們可以換一種思路,通過修改表的rowkey結構,將timestamp字段改成一個周期循環的timestamp,如取timestamp % TS_MODE后的值,其中TS_MODE須大於等於表的TTL時間周期,這樣才能保證數據不會被覆蓋掉。經過這樣改造后,即可實現Region的復用,避免Region的無限上漲。對於讀寫端的變更也較小,讀寫端操作時只需將timestamp字段取模后作為rowkey進行讀寫,另外,讀端需要考慮能適應scan掃描時處理[startTsMode, endTsMode]和[endTsMode, startTsMode]兩種情況。
4. 總結的話
以上僅是本人結合實際項目中遇到的問題進行了概括總結,僅供參考。歡迎討論交流。