天天看點

HBase最佳實踐-記憶體規劃

線上HBase叢集應該如何進行參數配置?這其實是很多HBase初學者在實踐環節都可能會遇到的問題,有些人會選擇預設配置,有些人會選擇其他公司的推薦配置;誠然,這樣的參數配置在大多數情況下都能正常工作,但性能卻未必最佳、資源未必都能被合理利用。本文結合筆者的實踐經驗,針對不同應用場景,對多種工作模式下的參數進行詳細說明,并結合相關示例對叢集規劃中最核心子產品-記憶體規劃進行介紹。一方面希望讀者能夠了解HBase記憶體相關知識細節,另一方面能夠将這些知識應用于實踐、不斷對叢集進行優化。

HBase中記憶體規劃直接涉及讀緩存BlockCache、寫緩存MemStore,影響系統記憶體使用率、IO使用率等資源以及讀寫性能等,重要性不言而喻。主要配置也是針對BlockCache和MemStore進行,然而針對不同業務類型(簡單說來主要包括讀多寫少型和寫多讀少型),記憶體的相關配置卻完全不同。再者,對于讀緩存BlockCache,線上一般會有兩種工作模式:LRUBlockCache和BucketCache,不同工作模式下的相關配置也不盡相同。為了比較完整的說明不同應用場景以及不同緩存工作模式的記憶體規劃,下文會分分别介紹兩個案列:讀多寫少型+BucketCache,寫多讀少型+LRUBlockCache。

需要說明的是,業務類型和讀緩存工作模式之間沒有任何直接的關聯。業務到底使用BucketCache還是使用LRUBlockCache,隻和配置設定給RegionServer的記憶體大小有關。一般而言,如果HBASE_HEAPSIZE > 20G,選擇BucketCache,否則選擇LRUBlockCache(參考hortonworks文檔),理論依據可以參考這裡。

記憶體分布圖

在詳細說明具體的容量規劃前,首先需要明确LRUBlockCache模式下的記憶體分布圖,如下圖所示:

HBase最佳實踐-記憶體規劃

圖中配置設定給RegionServer程序的記憶體就是JVM記憶體,主要分為三部分:LRUBlockCache,用于讀緩存;MemStore,用于寫緩存;Other,用于RS運作所必須的其他對象;

記憶體規劃思路

了解了BucketCache模式下的記憶體分布圖之後,我們具體來分析如何規劃記憶體,首先列出來基本條件:

a.  整個實體機記憶體:96G

b.  業務負載分布:30%讀,70%寫

接下來将問題一步一步分解,從上至下按照邏輯對記憶體進行規劃:

(1) 系統記憶體基礎上如何規劃RS記憶體?

這個問題需要根據自身伺服器情況決定,一般情況下,在不影響其他服務的情況下,越大越好。我們目前設定為64G,為系統記憶體的2/3。

(2) 如何設定LRUBlockCache、MemStore?

确定RegionServer總記憶體之後,接下來分别規劃LRUBlockCahce和MemStore的總記憶體。在此需要考慮兩點:在寫多讀少的業務場景下,寫緩存顯然應該配置設定更多記憶體,讀緩存相對配置設定更少;HBase在此處有個硬規定:LRUBlockCache + MemStore < 80% * JVM_HEAP,否則RS無法啟動。

推薦記憶體規劃:MemStore = 45% * JVM_HEAP = 64G * 45% = 28.8G ,LRUBlockCache = 30% * JVM_HEAP = 64G * 30% = 19.2G;預設情況下Memstore為40% * JVM_HEAP,而LRUBlockCache為25% * JVM_HEAP

 配置設定實踐

(1)設定JVM參數如下:

(2)hbase-site.xml中MemStore相關參數設定如下:

由上述定義可知,hbase.regionserver.global.memstore.upperLimit設定為0.45,hbase.regionserver.global.memstore.lowerLimit設定為0.40hbase.regionserver.global.memstore.upperLimit表示RegionServer中所有MemStore占有記憶體在JVM記憶體中的比例上限。如果所占比例超過這個值,RS會首先将所有Region按照MemStore大小排序,并按照由大到小的順序依次執行flush,直至所有MemStore記憶體總大小小于hbase.regionserver.global.memstore.lowerLimit,一般lowerLimit比upperLimit小5%。

(3)hbase-site.xml中LRUBlockCache相關參數設定如下:

hfile.block.cache.size表示LRUBlockCache占用記憶體在JVM記憶體中的比例,是以設定為0.3

與LRUBlockCache模式相比,BucketCache模式下的記憶體分布圖會更加複雜,如下圖所示:

HBase最佳實踐-記憶體規劃

如圖,整個RegionServer記憶體(Java程序記憶體)分為兩部分:JVM記憶體和堆外記憶體。其中JVM記憶體中LRUBlockCache和堆外記憶體BucketCache一起構成了讀緩存CombinedBlockCache,用于緩存讀到的Block資料,其中LRUBlockCache用于緩存中繼資料Block,BucketCache用于緩存實際使用者資料Block;MemStore用于寫流程,緩存使用者寫入KeyValue資料;還有部分用于RegionServer正常運作所必須的記憶體;

和案例一相同,本案例中實體機記憶體也是96G,不過業務類型為讀多寫少:70%讀+30%寫

因為BucketCache模式下記憶體分布圖相對複雜,我們使用如下表格一步一步對記憶體規劃進行解析:

序号

步驟

原理

計算公式

計算值

修正值

A

規劃RS總記憶體 

在系統記憶體允許且不影響其他服務的情況下,越多越好。設定為系統總記憶體的 2/3。

2/3 * 96G

64G

B

規劃讀緩存 CombinedBlockCache

整個RS記憶體分為三部分:讀緩存、寫緩存、其他。基本按照5 : 3 : 2的配置設定原則。讀緩存設定為整個RS記憶體的50%

A * 50%

32G

34G

B1

規劃讀緩存LRU部分

LRU部分主要緩存資料塊中繼資料,資料量相對較小。設定為整個讀緩存的10%

B * 10%

3.2G

3G

B2

規劃讀緩存BucketCache部分

BucketCache部分主要緩存使用者資料塊,資料量相對較大。設定為整個讀緩存的90%

B * 90%

28.8G

30G

C

規劃寫緩存MemStore

整個RS記憶體分為三部分:讀緩存、寫緩存、其他。基本按照5:4:1的配置設定原則。寫緩存設定為整個RS記憶體的40%

A * 30%

19.2G

20G

D

設定JVM_HEAP

RS總記憶體大小 – 堆外記憶體大小

A – B2 

35.2G

計算修正

看到這裡,可能很多仔細的朋友就會疑問,案例一不是說過HBase有一個硬規定麼:LRUBlockCache + MemStore < 80% * JVM_HEAP,否則RS無法啟動。不錯,HBase确實有這樣一個規定,這個規定的本質是為了在記憶體規劃的時候能夠給除過寫緩存和讀緩存之外的其他對象留夠至少20%的記憶體空間。那按照上述計算方式能不能滿足這個硬規定呢,(LRU + MemStore)/ JVM_HEAP =(3.2G + 19.2G)/ 35.2G = 22.4G / 35.2G =  63.6% ,遠小于80%。是以需要對計算值進行簡單的修正,适量減少JVM_HEAP值(減少至30G),增大Memstore到20G。因為JVM_HEAP減少了,堆外記憶體就需要适量增大,是以将BucketCache增大到30G。

調整之後,LRU + MemStore / JVM_HEAP = 3.2G + 20G / 30G = 23.2G / 30G =  77%

根據upperLimit參數的定義,結合上述記憶體規劃資料可計算出 upperLimit =  20G / 30G = 66%。是以upperLimit參數設定為0.66,lowerLimit設定為0.60

(3)hbase-site.xml中CombinedBlockCache相關參數設定如下:

按照上述介紹設定之後,所有關于記憶體相關的配置基本就完成了。但是需要特别關注一個參數hfile.block.cache.size,這個參數在本案例中并不需要設定,沒有任何意義。但是HBase的硬規定卻是按照這個參數計算的,這個參數的值加上hbase.regionserver.global.memstore.upperLimit的值不能大于0.8,上文提到hbase.regionserver.global.memstore.upperLimit值設定為0.66,是以,hfile.block.cache.size必須設定為一個小于0.14的任意值。hbase.bucketcache.ioengine表示bucketcache設定為offheap模式;hbase.bucketcache.size表示所有讀緩存占用記憶體大小,該值可以為記憶體真實值,機關為M,也可以為比例值,表示讀緩存大小占JVM記憶體大小比例。如果為記憶體真實值,則為34G,即34816。hbase.bucketcache.percentage.in.combinedcache參數表示用于緩存使用者資料塊的記憶體(堆外記憶體)占所有讀緩存的比例,設為0.90;

至此,關于HBase叢集的記憶體規劃經過兩個案例的分析到此就要結束了,希望看官能夠了解整個分析的思路。結合自己的應用場景以及記憶體使用模式對記憶體進行規劃。本文也隻是筆者個人見解,如果有任何意見可以互相交流讨論