2015年11月11日,作為媒體大屏(datav)、消費記錄、支付寶風控、物流詳情、庫存對賬核心資料庫的集團hbase,當天穩定運作,順利完成了任務。并交出了非常漂亮的幾項資料:qps=1993w,tps=3656w,讀流量=56gbps,寫流量=40.6gbps,全天吞吐讀2.0pb,寫1.28pb。
由于hbase團隊的組織架構變動,使得今年2015雙11的備戰重責落在了幾杆稚嫩的小槍身上了,不是雙11運維、開發新人就是應屆畢業生。備戰過程的『點』,若從db叢集老核心業務整合開始算起,戰役從今年5月就打響了第一槍。備戰過程的『面』,涉及支付寶、安全部、菜鳥、天貓、淘寶技術部、共享業務事業部、航旅、阿裡雲等幾乎所有bu。今年我想從hbase系統層面和業務層面兩個大方向談談整個備戰過程,對整個2015年進行一次較為全面的總結。
系統層面,經曆了從3u5.5至3u7.5.1的發展,磨砺出了七劍,為hbase系統的性能、穩定性、高可用、單元化保駕護航。所謂開發團隊制造彈藥,pe團隊落地優化。有了這些利劍和神兵,我們才能披荊斬棘所向披靡。
exploringcompaction成為預設選舉算法
replication的優化
單元化及diamond整合
mttr1期
限制大scan請求的資源使用
混合存儲
基于虛拟節點的跨zk叢集切庫
hbase本身有非常多的業務是以bulkload的方式進行離線資料寫入的,對應的在雲端插件為hbasebulkwriter,優點為對線上影響小(不占用服務端線程池),代價為丢失本地化率及帶來部分io毛刺。3u5.5之前的版本采用的預設檔案選擇政策,在bulkload的場景下存在缺陷,會導緻compaction積壓(io不能有效地去做檔案合并),檔案數無法控制,影響線上實時讀性能。3u5.5徹底完成了社群的exploring選舉算法的引入,極大優化了該場景甚至是泛化場景下的檔案compaction。
hbase是采用lsm樹作為存儲引擎的,compaction的目的是減少檔案數和删除無用的資料,優化讀性能,準則是用最小的io代價去減少最多的檔案數。compaction有2個原則:
所有storefile按照順序進行排列(此順序為:老檔案在前,新檔案在後。bulkload進來的檔案總是排在hbase内部生成的檔案之前。詳細的順序排列參考store#sortandclone);
參與compaction的檔案必須是連續的;
先來看看預設的選舉算法ratiobasedcompaction:
從storefile清單中,從老到新(即隊列中從頭到尾),挑選起始的那個storefile,挑選的依據是: 檔案大小不能超過配置中的max size(預設2gb),并且檔案大小不能超過後面檔案的大小sum*ratio(預設為1.2倍);
決定終止的storefile,一般就是清單中的最後一個檔案,但是要求參與compaction的檔案數不能超過配置的max files數目,預設為10個,如果超過10個了,那麼終止的storefile為 起始位置+max files ;
bulkload的場景下,會産生很多小檔案。舉個例子,典型的會有如下的file list(ratio=1):300mb(bulkload), 5mb(bulkload), 1gb, 23mb, 12mb, 12mb。那麼預設的ratio算法會選擇:5mb, 1gb, 23mb, 12mb, 12mb,這樣我們的io代價大,收效甚微(打開5個檔案句柄,讀1076mb,寫1076mb,減少4個檔案)。其實這樣的情況下,我們最想要得到的是: 23mb, 12mb, 12 mb。因為這樣是以最小的io代價(打開4個句柄,讀47mb、寫47mb),減少2個檔案。再舉個例子,flie list為:20mb(bulkload), 20mb(bulkload), 1gb, 4mb, 3mb, 2mb, 1mb,預設算法會選擇:20mb, 20mb, 1gb, 4mb, 3mb, 2mb, 1mb,打開8個句柄,讀1074mb、寫1074mb,減少6個檔案;但是我們想要的選擇是: 4mb, 3mb, 2mb, 1mb,打開5個句柄,讀10mb、寫10mb,減少3個檔案。
是以exploringcompaction算法就非常适合我們,檢查storefile清單的每一個子隊列,從中找出一個最優子隊列,參與compaction:
隊列中的每一個檔案符合ratio準則;
1條件下擁有更多的檔案數目 ;
1, 2 條件下擁有更小的檔案大小;
相較于預設的算法,exploring更為『智能』,是七劍中的莫問。
replication是hbase實作叢集内部同步的重要元件,是業務高可用、單元化的基礎,2015年我們主要在優化同步積壓和積壓影響組級别隔離兩方面做了努力。
主線程shipedits多線程化。alimonitor是雙11需要p1級别保障的業務,它的曆史監控繪圖資料存儲在hbase,日常是有主備實時同步進行高可用保障的,主庫主要有當機或者1分鐘以上的抖動,就會立刻執行切庫,保障系統的穩定。但是2015年年初,有一個問題困擾我們,就是alimonitor因為業務特性,存在和時間序列相關的持續熱點,這個熱點也不是很熱,大約就是其他節點的+10%。主備庫同步經常積壓,造成即使可以切庫,也會有大量監控繪圖有斷圖的現象。于是我們對replication進行了改造,用多線程的方式,将這些資料推送(shipedits)到備叢集的多台regionserver。即shipedits動作,由單線程改為多線程,而hlog的read動作,仍然保持單線程。受益的業務不僅包括alimonitor,也涉及到依賴中美同步的廣大ae和icbu的同胞們、以及所有單元化、高可用架構使用者。似七劍遊龍,攻勢兇猛,分分鐘消化同步積壓,為主備庫高可用保駕護航。
積壓影響組級别隔離。hbase早在2013年就開始了大叢集運維政策,一個業務或一個bu的業務隔離出一個分組,底層hdfs可以共享io,并且可以容易地進行資源排程。引入了replication後有一個問題,就是groupa的同步産生了積壓,會導緻備庫所有業務的同步資料積壓。是以,我們對其進行了改造,在選擇備庫代理發出put請求的伺服器時,指定在和主庫group name一緻分組下的機器中進行選擇。這樣即使groupa的同步積壓,也不會波及其他『無辜』的業務分組了。
異地多活、單元化等關鍵詞充斥着2015上半年,hbase也有部分業務涉及單元化的一中心、多單元的部署架構需求。3u7版本前的hbase隻支援主主(peer to peer)同步備份,無法支援單元化。
實作單元化過程中的主要通過資料打标的辦法解決了資料環路問題,并且開發出了一套可視化的運維控制台。replication的單元化功能上線後,可以支援如下圖的複雜部署,滿足單元化的需求:
并且,使用者可以選擇使用diamond的方式通路hbase叢集,利用diamond進行資料源位址推送,和單元化分流。多peer+diamond使得hbase似七劍天瀑,轉易颠倒,意到随成,資料做到真正的任意流轉,業務做到真正的異地多活。
對于分布式資料庫,單個節點當機(服務當機、實體當機)是一個可能會發生的常态。3u7版本前的hbase隻要跪一台regionserver,就會引起業務抖動近18分鐘。mttr優化一期,主要關注的是單台rs當機後的恢複過程優化和改進。單台regionserver當機的failover過程可以參看:http://blog.csdn.net/hljlzc2007/article/details/10963425。拿集團tt這樣體量的業務來說,mttr一期優化後,單台實體當機恢複時間縮短至了7分鐘。整個mttr似七劍青幹,象征“防守&迅捷”,快速恢複。其中,我們主要做了以下四項優化(資料隻是測試資料):
場景
改進前
改進後
split-log過程中過濾已flush的entry
耗時18 min
耗時5 min
普通rs和服務meta的rs先後當機,優先恢複meta region
耗時4 min
耗時35 sec
recoverlease機制優化
由worker進行lease recover
由master進行lease recover
避免hdfs故障導緻的rs當機
hdfs故障後1分鐘内rs abort
hdfs故障後rs不abort,且可繼續提供不涉及hdfs操作的讀寫服務
split hlog時過濾過時的edits/entry
該優化點主要是在split-log過程中生成recovered.edits時skip掉已經flush的entry,進而加速整個split過程。線上環境通常配置hbase.regionserver.maxlogs為96,也就是說hlog總大小為96*256mb,而memstore總大小通常不超過10gb,從這個角度看該特性應該可以在split-log時過濾掉一半以上資料。
當機時優先恢複meta region
該優化點針對的情況是當有兩台rs先後當機,後當機的rs上服務meta region且當機前存在建表/删表操作的情況下,加速meta region上線速度。優化後,我們會在每次處理掉一個split log task之後動态擷取任務清單(之前是靜态),并且優先處理meta region的相關的task。
該優化點主要針對split-log産生大量recovered.edits檔案導緻hdfs性能緩慢情況下recoverlease長期無法完成拖慢整體log split速度的問題,改進split-log過程中recoverlease的機制,加速failover。
hdfs故障導緻的rs當機
3u7之前,當hdfs出現問題時(例如網絡問題,進入safemode,或者整個hdfs叢集當機等),regionserver會很快檢測到(flush/hlog_roll都會觸發對filesystem的檢查)并abort,這樣帶來的最大問題是hdfs恢複後會有大量的split-log發生,導緻非常長的恢複時間。實際上,當hdfs出現問題時,可以捕捉相關異常,并死等hdfs恢複,在此期間讀寫仍可進行直至觸發hdfs操作。同時由于不觸發server abort,不會導緻split-log,是以可大大縮短恢複時間。實測效果顯示,hdfs故障1小時後恢複仍然可以保證hbase恢複并保證資料一緻性,這大大降低了hdfs故障的影響,并在最差情況下可以通過重新開機hdfs來解決故障,而不用擔心split-log及恢複時間過長的問題。
今年,支付寶消費記錄去了mysql,把所有實時查詢都搬上了hbase,是曆史以來責任最重的雙11,試想當你們支付寶支付完成之後,看不到消費轉賬記錄是何等的心情。但是,在年初的時候,消費記錄的hbase叢集,會經常遇到單台regionserver handler(線程池)打爆,load飙高至不可接受導緻服務當機的問題。消費記錄是一個從mysql遷移過來的應用,查詢場景包含了大量scan+filter,并且skip的kv異常多,查詢範圍廣。但凡有跨n多datablock的查詢,服務端總會把資源消耗在這種大查詢之上,導緻阻塞後續的查詢。大請求(bigcall)的定義:對系統資源消耗特别大的請求,典型的例子就是帶有filter的scan,這個filter過濾掉了大量的資料,導緻一個next操作會通路成百上千個block。當block大部分都在記憶體時,這種scan就會消耗大量資源。當多個大請求并發通路伺服器時,會造成load飙高,吞吐量下降。在實際的問題中,大請求可能幾個小時都執行不完。
是以我們針對性的對bigcall進行了截流,實作了bigcallthrottle。限制大請求的資源消耗,讓正常的請求可以擷取資源。通過sleep達到目的。中斷掉對用戶端來說已經逾時的請求,這種請求繼續運作沒有意義。中斷請求釋放資源。優化似七劍舍神,使得服務端具有強烈的生命力。經過優化,消費記錄在之後的曆次大促和雙11中,系統非常穩定,沒有出現過因大請求導緻的服務當機,業務抖動。
混合存儲是2015年強推的一個大優化,似七劍日月,是最耀眼的優化。随着集團hbase承接業務範圍的擴大,越來越多實時性要求高(99.9% 200ms内)、資料海量(往往超過幾十tb)的業務在硬體選擇上遇到了難題:
選擇sata?高毛刺高rt,低下的iops能力,肯定不行。
選擇ssd?高昂的資源開銷,這個也承受不住,并且存儲空間也還是問題。
選擇混合存儲機型的ssd做二級緩存?不同的業務具有不同的命中率,無法提升命中率則一旦抖到sata盤上還是然并卵。我們是要做一種通用的解決方案,這也不行。
在尋求硬體開銷&性能&存儲空間的tradeoff中,我們想到了真正的混合存儲:12個硬碟slot中有3個是ssd,其餘9個是sata。資料寫入的時候,可以指定寫入1份ssd還是3份,抑或不寫,讀取的時候可以選擇是否優先走ssd讀。這個功能一上線,太多太多的業務都争先恐後上去,目前集團+支付寶已經有30%的機器被替換成了混合存儲,在預算持平的情況下,讀rt從99% 200ms優化至99.9% 200ms,使用者體驗上升。
3u7.1之前的hbase用戶端隻能進行同zk叢集下基于虛拟節點的切庫。但是有幾個問題需要解決:
老叢集業務平滑遷移,即使用戶端改造為虛拟節點的方式連接配接zk,仍不能保證過程透明;
單元沒有提供2:2:1部署zk叢集條件的,必須進行跨zk叢集多單元部署的情況;
基于diamond的高可用架構下,但凡diamond本身無法保障高可用的情況;
基于以上三種場景,我們需要基于虛拟節點的跨zk叢集切庫這一功能。這在正如衣服内短小的競星劍,非必要時刻不出手,出手時迅雷不及掩耳。