本篇文章來講道說道如何診斷HBase寫數據的異常問題以及優化寫性能。和讀相比,HBase寫數據流程卻是顯得很簡單:數據先順序寫入HLog,再寫入對應的緩存Memstore,當Memstore中數據大小達到必定閾值(128M)以後,系統會異步將Memstore中數據flush到HDFS造成小文件。java
開發者盛宴來襲!7月28日51CTO首屆開發者大賽決賽帶來技術創新分享
本篇文章來講道說道如何診斷HBase寫數據的異常問題以及優化寫性能。和讀相比,HBase寫數據流程卻是顯得很簡單:數據先順序寫入HLog,再寫入對應的緩存Memstore,當Memstore中數據大小達到必定閾值(128M)以後,系統會異步將Memstore中數據flush到HDFS造成小文件。算法
HBase數據寫入一般會遇到兩類問題,一類是寫性能較差,另外一類是數據根本寫不進去。這兩類問題的切入點也不盡相同,以下圖所示:apache
寫性能優化切入點緩存
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大小對寫入性能影響曲線圖以下:
圖中橫座標是寫入的一行數據(每行數據10列)大小,左縱座標是寫入吞吐量,右座標是寫入平均延遲(ms)。能夠看出隨着單行數據大小不斷變大,寫入吞吐量急劇降低,寫入延遲在100K以後急劇增大。
說到這裏,有必要和你們分享兩起在生產線環境由於業務KeyValue較大致使的嚴重問題,一塊兒是由於大字段業務寫入致使其餘業務吞吐量急劇降低,另外一起是由於大字段業務scan致使RegionServer宕機。
案件一:大字段寫入致使其餘業務吞吐量急劇降低
部分業務反饋集羣寫入突然變慢、數據開始堆積的狀況,查看集羣表級別的數據讀寫QPS監控,發現問題的第一個關鍵點:業務A開始寫入以後整個集羣其餘部分業務寫入QPS都幾乎斷崖式下跌,初步懷疑黑手就是業務A。
下圖是當時業務A的寫入QPS(過後發現腦殘忘了截取其餘表QPS斷崖式下跌的慘象),可是第一感受是QPS並不高啊,憑什麼去影響別人!
因而就繼續查看其餘監控信息,首先確認系統資源(主要是IO)並無到達瓶頸,其次確認了寫入的均衡性,直至看到下圖,才追蹤到影響其餘業務寫入的第二個關鍵點:RegionServer的handler(配置150)被殘暴耗盡:
對比上面兩張圖,是否是發現出奇的一致,那就能夠基本確認是因爲該業務寫入致使這臺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」,以下圖所示:
緣由分析:經過查看源碼以及相關文檔,確認該異常發生在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寫入性能優化以及寫入異常問題的一些理解,若有紕漏,還望指正!另外,若是你們有任何關於此話題的案例也很歡迎一塊兒討論~