Datastream一直以來在使用HBase分流日誌,天天的數據量很大,日均大概在80億條,10TB的數據。對於像Datastream這種數據量巨大、對寫入要求很是高,而且沒有複雜查詢需求的日誌系統來講,選用HBase做爲其數據存儲平臺,無疑是一個很是不錯的選擇。java
HBase是一個相對較複雜的分佈式系統,併發寫入的性能很是高。然而,分佈式系統從結構上來說,也相對較複雜,模塊繁多,各個模塊之間也很容易出現一些問題,因此對像HBase這樣的大型分佈式系統來講,優化系統運行,及時解決系統運行過程當中出現的問題也變得相當重要。正所謂:「你」若安好,即是晴天;「你」如有恙,我便沒有星期天。apache
HBase交接到咱們團隊手上時,已經在線上運行有一大段時間了,期間也偶爾聽到過系統不穩定的、時常會出現一些問題的言論,但咱們認爲:一個能被大型互聯網公司普遍採用的系統(包括Facebook,twitter,淘寶,小米等),其在性能和可用性上是毋庸置疑的,況且像Facebook這種公司,是在通過嚴格選型後,放棄了本身開發的Cassandra系統,用HBase取而代之。既然這樣,那麼,HBase的不穩定、常常出問題必定有些其餘的緣由,咱們所要作的,就是找出這些HBase的不穩定因素,還HBase一個「清白」。「查案」以前,先來簡單回顧一下咱們接手HBase時的現狀(咱們運維着好幾個HBase集羣,這裏主要介紹問題最多那個集羣的調優):服務器
名稱網絡 |
數量併發 |
備註運維 |
服務器數量分佈式 |
17oop |
配置不一樣,HBase、HDFS都部署在這些機器上性能 |
表數量測試 |
30+ |
只有部分表的數據量比較大,其餘基本沒多少數據 |
Region數量 |
600+ |
基本上都是數據量較大的表劃分的region較多 |
請求量 |
50000+ |
服務器請求分佈極其不均勻 |
應用反應常常會過段時間出現數據寫入緩慢,致使應用端數據堆積現象,是否能夠經過增長機器數量來解決?
其實,那個時候,咱們自己對HBase也不是很熟悉,對HBase的瞭解,也僅僅在作過一些測試,瞭解一些性能,對內部結構,實現原理之類的基本上都不怎麼清楚。因而剛開始幾天,各類問題,天天晚上拉着一男一塊兒摸索,順利的時候,晚上8,9點就能夠暫時搞定線上問題,更多的時候基本要到22點甚至更晚(可能那個時候流量也下去了),經過不斷的摸索,慢慢了解HBase在使用上的一些限制,也就能逐漸解決這一系列過程當中發現的問題。後面挑幾個相對比較重要,效果較爲明顯的改進點,作下簡單介紹。
首先根據目前17臺機器,50000+的QPS,而且觀察磁盤的I/O利用率和CPU利用率都至關低來判斷:當前的請求數量根本沒有達到系統的性能瓶頸,不須要新增機器來提升性能。若是不是硬件資源問題,那麼性能的瓶頸到底是什麼?
打開HBase的Web端,發現HBase下面各個RegionServer的請求數量很是不均勻,第一個想到的就是HBase的熱點問題,具體到某個具體表上的請求分佈以下:
HBase表請求分佈
上面是HBase下某張表的region請求分佈狀況,從中咱們明顯能夠看到,部分region的請求數量爲0,而部分的請求數量能夠上百萬,這是一個典型的熱點問題。
HBase出現熱點問題的主要緣由無非就是rowkey設計的合理性,像上面這種問題,若是rowkey設計得很差,很容易出現,好比:用時間戳生成rowkey,因爲時間戳在一段時間內都是連續的,致使在不一樣的時間段,訪問都集中在幾個RegionServer上,從而形成熱點問題。
知道了問題的緣由,對症下藥便可,聯繫應用修改rowkey規則,使rowkey數據隨機均勻分佈,效果以下:
Rowkey重定義後請求分佈
對於HBase來講,rowkey的範圍劃定了RegionServer,每一段rowkey區間對應一個RegionServer,咱們要保證每段時間內的rowkey訪問都是均勻的,因此咱們在設計的時候,儘可能要以hash或者md5等開頭來組織rowkey。
HBase的集羣是在不斷擴展的,分佈式系統的最大好處除了性能外,不停服橫向擴展也是其中之一,擴展過程當中有一個問題:每次擴展的機器的配置是不同的,通常,後面新加入的機器性能會比老的機器好,可是後面加入的機器常常被分配不多的region,這樣就形成了資源分佈不均勻,隨之而來的就是性能上的損失,以下:
HBase各個RegionServer請求
上圖中咱們能夠看到,每臺RegionServer上的請求極爲不均勻,多的好幾千,少的只有幾十
資源分配不均勻,形成部分機器壓力較大,部分機器負載較低,而且部分Region過大過熱,致使請求相對較集中。
遷移部分老的RegionServer上的region到新加入的機器上,使每一個RegionServer的負載均勻。經過split切分部分較大region,均勻分佈熱點region到各個RegionServer上。
HBase region請求分佈
對比先後兩張截圖咱們能夠看到,Region總數量從1336增長到了1426,而增長的這90個region就是經過split切分大的region獲得的。而對region從新分佈後,整個HBase的性能有了大幅度提升。
Region遷移的時候不能簡單開啓自動balance,由於balance主要的問題是不會根據表來進行balance,HBase的自動balance只會根據每一個RegionServer上的Region數量來進行balance,因此自動balance可能會形成同張表的region會被集中遷移到同一個臺RegionServer上,這樣就達不到分佈式的效果。
基本上,新增RegionServer後的region調整,能夠手工進行,儘可能使表的Region都平均分配到各個RegionServer上,另一點,新增的RegionServer機器,配置最好與前面的一致,不然資源沒法更好利用。
對於過大,過熱的region,能夠經過切分的方法生成多個小region後均勻分佈(注意:region切分會觸發major compact操做,會帶來較大的I/O請求,請務必在業務低峯期進行)
HBase寫入緩慢,查看HBase日誌,常常有慢日誌以下:
WARN org.apache.hadoop.ipc.HBaseServer- (responseTooSlow): {"processingtimems":36096, "call":"multi(org.apache.hadoop.hbase.client.MultiAction@7884377e), rpc version=1, client version=29, methodsFingerPrint=1891768260", "client":"xxxx.xxx.xxx.xxxx:44367", "starttimems":1440239670790, "queuetimems":42081, "class":"HRegionServer", "responsesize":0, "method":"multi"}
而且伴有HDFS建立block異常以下:
INFO org.apache.hadoop.hdfs.DFSClient - Exception in createBlockOutputStream
org.apache.hadoop.hdfs.protocol.HdfsProtoUtil.vintPrefixed(HdfsProtoUtil.java:171)
org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.createBlockOutputStream(DFSOutputStream.java:1105)
org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.nextBlockOutputStream(DFSOutputStream.java:1039)
org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.run(DFSOutputStream.java:487)
通常地,HBase客戶端的寫入到RegionServer下某個region的memstore後就返回,除了網絡外,其餘都是內存操做,應該不會有長達30多秒的延遲,外加HDFS層拋出的異常,咱們懷疑極可能跟底層數據存儲有關。
定位到多是HDFS層出現了問題,那就先從底層開始排查,發現該臺機器上10塊盤的空間利用率都已經達到100%。按理說,做爲一個成熟的分佈式文件系統,對於部分數據盤滿的狀況,應該有其應對措施。的確,HDFS自己能夠設置數據盤預留空間,若是部分數據盤的預留空間小於該值時,HDFS會自動把數據寫入到另外的空盤上面,那麼咱們這個又是什麼狀況?
最終經過多方面的溝通確認,發現了主要緣由:咱們這批機器,在上線前SA已經通過處理,每塊盤默認預留100G空間,因此當經過df命令查看盤使用率爲100%時,其實盤還有100G的預留空間,而HDFS層面咱們配置的預留空間是50G,那麼問題就來了:HDFS認爲盤還有100G空間,而且多於50G的預留,因此數據能夠寫入本地盤,可是系統層面卻禁止了該寫入操做,從而致使數據寫入異常。
解決的方法可讓SA釋放些空間出來便於數據寫入。固然,最直接有效的就是把HDFS的預留空間調整至100G以上,咱們也正是這樣作的,經過調整後,異常再也不出現,HBase層面的slow log也沒有再出現。同時咱們也開啓了HDFS層面的balance,使數據自動在各個服務器之間保持平衡。
磁盤滿了致使的問題很難預料,HDFS可能會致使部分數據寫入異常,MySQL可能會出現直接宕機等等,因此最好的辦法就是:不要使盤的利用率達到100%。
經過rowkey調整,HDFS數據balance等操做後,HBase的確穩定了許多,在很長一段時間都沒有出現寫入緩慢問題,總體的性能也上漲了不少。但時常會隔一段時間出現些slow log,雖然對總體的性能影響不大,但性能上的抖動仍是很明顯。
因爲該問題不常常出現,對系統的診斷帶來不小的麻煩,排查了HBase層和HDFS層,幾乎一無所得,由於在大多數狀況下,系統的吞吐量都是正常的。經過腳本收集RegionServer所在服務器的系統資源信息,也看不出問題所在,最後懷疑到系統的物理拓撲上,HBase集羣的最大特色是數據量巨大,在作一些操做時,很容易把物理機的千兆網卡都吃滿,這樣若是網絡拓撲結構存在問題,HBase的全部機器沒有部署在同一個交換機上,上層交換機的進出口流量也有可能存在瓶頸。網絡測試仍是挺簡單的,直接ping就能夠,咱們獲得如下結果:共17臺機器,只有其中一臺的延遲存在問題,以下:
網絡延遲測試:Ping結果
同一個局域網內的機器,延遲達到了毫秒級別,這個延遲是比較致命的,由於分佈式存儲系統HDFS自己對網絡有要求,HDFS默認3副本存在不一樣的機器上,若是其中某臺機器的網絡存在問題,這樣就會影響到該機器上保存副本的寫入,拖慢整個HDFS的寫入速度。
網絡問題,聯繫機房解決,機房的反饋也驗證了咱們的想法:因爲HBase的機器後面進行了擴展,後面加入的機器有一臺跟其餘機器不在同一個交換機下,而這臺機器正是咱們找出的有較大ping延時這臺,整個HBase物理結構以下:
HBase物理拓撲結構
跟機房協調,調整機器位置,使全部的HBase機器都位於同一個交換機下,問題迎刃而解。
對於分佈式大流量的系統,除了系統自己,物理機的部署和流量規劃也至關重要,儘可能使集羣中全部的機器位於相同的交換機下(有容災需求的應用除外),集羣較大,須要跨交換機部署時,也要充分考慮交換機的出口流量是否夠用,網絡硬件上的瓶頸診斷起來相對更爲困難。
解決了網絡上面的不穩定因素,HBase的性能又獲得進一步的提升,隨之也帶來了另外的問題。
根據應用反應,HBase會階段性出現性能降低,致使應用數據寫入緩慢,形成應用端的數據堆積,這又是怎麼回事?通過一系列改善後HBase的系統較之之前有了大幅度增加,怎麼還會出現數據堆積的問題?爲何會階段性出現?
從上圖看,HBase平均流量QPS基本能達到12w,可是每過一段時間,流量就會降低到接近零點,同時這段時間,應用會反應數據堆積。
這個問題定位相對仍是比較簡單,結合HBase的日誌,很容易找到問題所在:
org.apache.hadoop.hbase.util.Sleeper - We slept 41662ms instead of 3000ms, this is likely due to a long garbage collecting pause and it's usually bad
經過上述日誌,基本上能夠斷定是HBase的某臺RegionServer出現GC問題,致使了服務在很長一段時間內禁止訪問。
HBase經過一系列的調整後,整個系統的吞吐量增長了好幾倍,然而JVM的堆大小沒有進行相應的調整,整個系統的內存需求變大,而虛擬機又來不及回收,最終致使出現Full GC
GC問題致使HBase整個系統的請求降低,經過適當調整JVM參數的方式,解決HBase RegionServer的GC問題。
對於HBase來講,自己不存在單點故障,即便宕掉1,2臺RegionServer,也只是使剩下幾臺的壓力有所增長,不會致使整個集羣服務能力降低不少。可是,若是其中某臺RegionServer出現Full GC問題,那麼這臺機器上全部的訪問都會被掛起,客戶端請求通常都是batch發送的,rowkey的隨機分佈致使部分請求會落到該臺RegionServer上,這樣該客戶端的請求就會被阻塞,致使客戶端沒法正常寫數據到HBase。因此,對於HBase來講,宕機並不可怕,但長時間的Full GC是比較致命的,配置JVM參數的時候,儘可能要考慮避免Full GC的出現。
通過前面一系列的優化,目前Datastream的這套HBase線上環境已經至關穩定,連續運行幾個月都沒有任何HBase層面因爲系統性能不穩定致使的報警,平均性能在各個時間段都比較穩定,沒有出現過大幅度的波動或者服務不可用等現象。
本文來自網易雲社區,經做者蔣鴻翔受權發佈。