1. 程式人生 > >HBase最佳實踐-HBase中的寫效能優化策略

HBase最佳實踐-HBase中的寫效能優化策略

 

2016年12月10日 14:37:03 ourpush 閱讀數:1452

 

上一篇文章主要介紹了HBase讀效能優化的基本套路,本篇文章來說道說道如何診斷HBase寫資料的異常問題以及優化寫效能。和讀相比,HBase寫資料流程倒是顯得很簡單:資料先順序寫入HLog,再寫入對應的快取Memstore,當Memstore中資料大小達到一定閾值(128M)之後,系統會非同步將Memstore中資料flush到HDFS形成小檔案。

 

HBase資料寫入通常會遇到兩類問題,一類是寫效能較差,另一類是資料根本寫不進去。這兩類問題的切入點也不盡相同,如下圖所示:

70

 

 

寫效能優化切入點

 

1. 是否需要寫WAL?WAL是否需要同步寫入?

優化原理:資料寫入流程可以理解為一次順序寫WAL+一次寫快取,通常情況下寫快取延遲很低,因此提升寫效能就只能從WAL入手。WAL機制一方面是為了確保資料即使寫入快取丟失也可以恢復,另一方面是為了叢集之間非同步複製。預設WAL機制開啟且使用同步機制寫入WAL。首先考慮業務是否需要寫WAL,通常情況下大多數業務都會開啟WAL機制(預設),但是對於部分業務可能並不特別關心異常情況下部分資料的丟失,而更關心資料寫入吞吐量,比如某些推薦業務,這類業務即使丟失一部分使用者行為資料可能對推薦結果並不構成很大影響,但是對於寫入吞吐量要求很高,不能造成資料佇列阻塞。這種場景下可以考慮關閉WAL寫入,寫入吞吐量可以提升2x~3x。退而求其次,有些業務不能接受不寫WAL,但可以接受WAL非同步寫入,也是可以考慮優化的,通常也會帶來1x~2x的效能提升。

 

優化推薦:根據業務關注點在WAL機制與寫入吞吐量之間做出選擇

 

其他注意點:對於使用Increment操作的業務,WAL可以設定關閉,也可以設定非同步寫入,方法同Put類似。相信大多數Increment操作業務對WAL可能都不是那麼敏感~

 

2. Put是否可以同步批量提交?

優化原理:HBase分別提供了單條put以及批量put的API介面,使用批量put介面可以減少客戶端到RegionServer之間的RPC連線數,提高寫入效能。另外需要注意的是,批量put請求要麼全部成功返回,要麼丟擲異常。

優化建議:使用批量put進行寫入請求

 

3. Put是否可以非同步批量提交?

優化原理:業務如果可以接受異常情況下少量資料丟失的話,還可以使用非同步批量提交的方式提交請求。提交分為兩階段執行:使用者提交寫請求之後,資料會寫入客戶端快取,並返回使用者寫入成功;當客戶端快取達到閾值(預設2M)之後批量提交給RegionServer。需要注意的是,在某些情況下客戶端異常的情況下快取資料有可能丟失。

 

優化建議:在業務可以接受的情況下開啟非同步批量提交

 

使用方式:setAutoFlush(false)

 

4. Region是否太少?

優化原理:當前叢集中表的Region個數如果小於RegionServer個數,即Num(Region of Table) < Num(RegionServer),可以考慮切分Region並儘可能分佈到不同RegionServer來提高系統請求併發度,如果Num(Region of Table) > Num(RegionServer),再增加Region個數效果並不明顯。

優化建議:在Num(Region of Table) < Num(RegionServer)的場景下切分部分請求負載高的Region並遷移到其他RegionServer;

5. 寫入請求是否不均衡?

優化原理:另一個需要考慮的問題是寫入請求是否均衡,如果不均衡,一方面會導致系統併發度較低,另一方面也有可能造成部分節點負載很高,進而影響其他業務。分散式系統中特別害怕一個節點負載很高的情況,一個節點負載很高可能會拖慢整個叢集,這是因為很多業務會使用Mutli批量提交讀寫請求,一旦其中一部分請求落到該節點無法得到及時響應,就會導致整個批量請求超時。因此不怕節點宕掉,就怕節點奄奄一息!

優化建議:檢查RowKey設計以及預分割槽策略,保證寫入請求均衡。

6. 寫入KeyValue資料是否太大?

KeyValue大小對寫入效能的影響巨大,一旦遇到寫入效能比較差的情況,需要考慮是否由於寫入KeyValue資料太大導致。KeyValue大小對寫入效能影響曲線圖如下:

72

 

圖中橫座標是寫入的一行資料(每行資料10列)大小,左縱座標是寫入吞吐量,右座標是寫入平均延遲(ms)。可以看出隨著單行資料大小不斷變大,寫入吞吐量急劇下降,寫入延遲在100K之後急劇增大。

說到這裡,有必要和大家分享兩起在生產線環境因為業務KeyValue較大導致的嚴重問題,一起是因為大欄位業務寫入導致其他業務吞吐量急劇下降,另一起是因為大欄位業務scan導致RegionServer宕機。

案件一:大欄位寫入導致其他業務吞吐量急劇下降

部分業務反饋叢集寫入忽然變慢、資料開始堆積的情況,檢視叢集表級別的資料讀寫QPS監控,發現問題的第一個關鍵點:業務A開始寫入之後整個叢集其他部分業務寫入QPS都幾乎斷崖式下跌,初步懷疑黑手就是業務A。

下圖是當時業務A的寫入QPS(事後發現腦殘忘了擷取其他表QPS斷崖式下跌的慘象),但是第一感覺是QPS並不高啊,憑什麼去影響別人!

73

 

於是就繼續檢視其他監控資訊,首先確認系統資源(主要是IO)並沒有到達瓶頸,其次確認了寫入的均衡性,直至看到下圖,才追蹤到影響其他業務寫入的第二個關鍵點:RegionServer的handler(配置150)被殘暴耗盡:

74

 

對比上面兩張圖,是不是發現出奇的一致,那就可以基本確認是由於該業務寫入導致這臺RegionServer的handler被耗盡,進而其他業務拿不到handler,自然寫不進去。那問題來了,為什麼會這樣?正常情況下handler在處理完客戶端請求之後會立馬釋放,唯一的解釋是這些請求的延遲實在太大。

試想,我們去漢堡店排隊買漢堡,有150個視窗服務,正常情況下大家買一個很快,這樣150個視窗可能只需要50個服務。假設忽然來了一批大漢,要定製超大漢堡,好了,所有的視窗都工作起來,而且因為大漢堡不好製作導致服務很慢,這樣必然會導致其他排隊的使用者長時間等待,直至超時。

可回頭一想這可是寫請求啊,怎麼會有這麼大的請求延遲!和業務方溝通之後確認該表主要儲存語料庫文件資訊,都是平均100K左右的資料,是不是已經猜到了結果,沒錯,就是因為這個業務KeyValue太大導致。KeyValue太大會導致HLog檔案寫入頻繁切換、flush以及compaction頻繁觸發,寫入效能急劇下降。

目前針對這種較大KeyValue寫入效能較差的問題還沒有直接的解決方案,好在社群已經意識到這個問題,在接下來即將釋出的下一個大版本HBase 2.0.0版本會針對該問題進行深入優化,詳見HBase MOB,優化後用戶使用HBase儲存文件、圖片等二進位制資料都會有極佳的效能體驗。

案件二:大欄位scan導致RegionServer宕機

案件現場:有段時間有個0.98叢集的RegionServer經常頻繁宕機,檢視日誌是由於”java.lang.OutOfMemoryError: Requested array size exceeds VM limit”,如下圖所示:

76

 

原因分析:通過檢視原始碼以及相關文件,確認該異常發生在scan結果資料回傳給客戶端時由於資料量太大導致申請的array大小超過JVM規定的最大值( Interge.Max_Value-2)。造成該異常的兩種最常見原因分別是:

 

  • 表列太寬(幾十萬列或者上百萬列),並且scan返回沒有對列數量做任何限制,導致一行資料就可能因為包含大量列而資料超過array大小閾值
  • KeyValue太大,並且scan返回沒有對返回結果大小做任何限制,導致返回資料結果大小超過array大小閾值

有的童鞋就要提問啦,說如果已經對返回結果大小做了限制,在表列太寬的情況下是不是就可以不對列數量做限制呢。這裡需要澄清一下,如果不對列資料做限制,資料總是一行一行返回的,即使一行資料大小大於設定的返回結果限制大小,也會返回完整的一行資料。在這種情況下,如果這一行資料已經超過array大小閾值,也會觸發OOM異常。

 

解決方案:目前針對該異常有兩種解決方案,其一是升級叢集到1.0,問題都解決了。其二是要求客戶端訪問的時候對返回結果大小做限制(scan.setMaxResultSize(2*1024*1024))、並且對列數量做限制(scan.setBatch(100)),當然,0.98.13版本以後也可以對返回結果大小在伺服器端進行限制,設定引數hbase.server.scanner.max.result.size即可

寫異常問題檢查點

 

上述幾點主要針對寫效能優化進行了介紹,除此之外,在一些情況下還會出現寫異常,一旦發生需要考慮下面兩種情況(GC引起的不做介紹):

 

Memstore設定是否會觸發Region級別或者RegionServer級別flush操作?

 

問題解析:以RegionServer級別flush進行解析,HBase設定一旦整個RegionServer上所有Memstore佔用記憶體大小總和大於配置檔案中upperlimit時,系統就會執行RegionServer級別flush,flush演算法會首先按照Region大小進行排序,再按照該順序依次進行flush,直至總Memstore大小低至lowerlimit。這種flush通常會block較長時間,在日誌中會發現“Memstore is above high water mark and block 7452 ms”,表示這次flush將會阻塞7s左右。

 

問題檢查點:

  • Region規模與Memstore總大小設定是否合理?如果RegionServer上Region較多,而Memstore總大小設定的很小(JVM設定較小或者upper.limit設定較小),就會觸發RegionServer級別flush。叢集規劃相關內容可以參考文章《》
  • 列族是否設定過多,通常情況下表列族建議設定在1~3個之間,最好一個。如果設定過多,會導致一個Region中包含很多Memstore,導致更容易觸到高水位upperlimit

 

Store中HFile數量是否大於配置引數blockingStoreFile?

 

問題解析:對於資料寫入很快的叢集,還需要特別關注一個引數:hbase.hstore.blockingStoreFiles,此引數表示如果當前hstore中檔案數大於該值,系統將會強制執行compaction操作進行檔案合併,合併的過程會阻塞整個hstore的寫入。通常情況下該場景發生在資料寫入很快的情況下,在日誌中可以發現”Waited 3722ms on a compaction to clean up ‘too many store  files“

 

問題檢查點:

  • 引數設定是否合理?hbase.hstore.compactionThreshold表示啟動compaction的最低閾值,該值不能太大,否則會積累太多檔案,一般建議設定為5~8左右。hbase.hstore.blockingStoreFiles預設設定為7,可以適當調大一些。

 

寫效能還能再提高麼?

 

上文已經從寫效能優化以及寫異常診斷兩個方面對HBase中資料寫入可能的問題進行了詳細的解釋,相信在0.98版本的基礎上對寫入來說已經是最好的解決方案了。但是有些業務可能依然覺得不夠快,畢竟”更快”是所有儲存系統活著的動力,那還有提高空間嗎?當然,接下來簡單介紹HBase之後版本對寫效能優化的兩點核心改進:

 

  • Utilize Flash storage for WAL(HBASE-12848)

這個特性意味著可以將WAL單獨置於SSD上,這樣即使在預設情況下(WALSync),寫效能也會有很大的提升。需要注意的是,該特性建立在HDFS 2.6.0+的基礎上,HDFS以前版本不支援該特性。具體可以參考官方jira:https://issues.apache.org/jira/browse/HBASE-12848

 

  • Multiple WALs(HBASE-14457)

該特性也是對WAL進行改造,當前WAL設計為一個RegionServer上所有Region共享一個WAL,可以想象在寫入吞吐量較高的時候必然存在資源競爭,降低整體效能。針對這個問題,社群小夥伴(阿里巴巴大神)提出Multiple WALs機制,管理員可以為每個Namespace下的所有表設定一個共享WAL,通過這種方式,寫效能大約可以提升20%~40%左右。具體可以參考官方jira:https://issues.apache.org/jira/browse/HBASE-14457

 

 

好了,這篇文章和大家一起分享了個人對HBase寫入效能優化以及寫入異常問題的一些理解,如有紕漏,還望指正!另外,如果大家有任何關於此話題的案例也很歡迎一起討論~

原文:http://hbasefly.com/2016/12/10/hbase-parctice-write/?utm_source=tuicool&utm_medium=referral