本文從HBase的內存佈局提及,先充分了解HBase的內存區的使用與分配,隨後給出了不一樣業務場景下的讀寫內存分配規劃,並指導如何分析業務的內存使用狀況,以及在使用當中寫內存Memstore及讀內存擴展bucketcache的一些注意事項,最後爲了保障羣集的穩定性減小和下降GC對於集羣穩定性的影響,研究及分享了一些關於HBase JVM配置的一些關鍵參數機器做用和範例,但願這些不斷充實的經驗能確保HBase集羣的穩定性能更上一個臺階,你們有任何的想法和建議也歡迎一塊兒討論。java
一臺region server的內存使用(以下圖所示)主要分紅兩部分:算法
1.JVM內存即咱們一般俗稱的堆內內存,這塊內存區域的大小分配在HBase的環境腳本中設置,在堆內內存中主要有三塊內存區域,shell
2.java direct memory即堆外內存,緩存
在詳細說明具體的容量規劃前,首先要明確on heap模式下的內存分佈圖,以下圖所示:數據結構
如圖,整個RegionServer內存就是JVM所管理的內存,BlockCache用於讀緩存;MemStore用於寫流程,緩存用戶寫入KeyValue數據;還有部分用於RegionServer正常RPC請求運行所必須的內存;併發
步驟 | 原理 | 計算 | 值 |
---|---|---|---|
jvm_heap | 系統總內存的 2/3 | 128G/3*2 | 80G |
blockcache | 讀緩存 | 80G*30% | 24G |
memstore | 寫緩存 | 80G*45% | 36G |
hbase-site.xmllless
<property> <name>hbase.regionserver.global.memstore.size</name> <value>0.45</value> </property> <property> <name>hfile.block.cache.size</name> <value>0.3</value> </property>
與 on heap模式相比,讀多寫少型須要更多的讀緩存,在對讀請求響應時間沒有太嚴苛的狀況下,會開啓off heap即啓用堆外內存的中的bucket cache做爲讀緩存的補充,以下圖所示jvm
整個RegionServer內存分爲兩部分:JVM內存和堆外內存。其中JVM內存中BlockCache和堆外內存BucketCache一塊兒構成了讀緩存CombinedBlockCache,用於緩存讀到的Block數據,其中BlockCache用於緩存Index Block和Bloom Block,BucketCache用於緩存實際用戶數據Data Blockoop
步驟 | 原理 | 計算 | 值 |
---|---|---|---|
RS總內存 | 系統總內存的 2/3 | 128G/3*2 | 80G |
combinedBlockCache | 讀緩存設置爲整個RS內存的70% | 80G*70% | 56G |
blockcache | 主要緩存數據塊元數據,數據量相對較小。設置爲整個讀緩存的10% | 56G*10% | 6G |
bucketcache | 主要緩存用戶數據塊,數據量相對較大。設置爲整個讀緩存的90% | 56G*90% | 50G |
memstore | 寫緩存設置爲jvm_heap的60% | 30G*60% | 18G |
jvm_heap | rs總內存-堆外內存 | 80G-50G | 30G |
參數詳解佈局
Property | Default | Description |
---|---|---|
hbase.bucketcache.combinedcache.enabled | true | When BucketCache is enabled, use it as a L2 cache for LruBlockCache. If set to true, indexes and Bloom filters are kept in the LruBlockCache and the data blocks are kept in the BucketCache. |
hbase.bucketcache.ioengine | none | Where to store the contents of the BucketCache. Its value can be offheap、heap、file |
hfile.block.cache.size | 0.4 | A float between 0.0 and 1.0. This factor multiplied by the Java heap size is the size of the L1 cache. In other words, the percentage of the Java heap to use for the L1 cache. |
hbase.bucketcache.size | not set | When using BucketCache, this is a float that represents one of two different values, depending on whether it is a floating-point decimal less than 1.0 or an integer greater than 1.0. |
-XX:MaxDirectMemorySize | MaxDirectMemorySize = BucketCache + 1 | A JVM option to configure the maximum amount of direct memory available for the JVM. It is automatically calculated and configured based on the following formula: MaxDirectMemorySize = BucketCache size + 1 GB for other features using direct memory, such as DFSClient. For example, if the BucketCache size is 8 GB, it will be -XX:MaxDirectMemorySize=9G. |
hbase-site.xml
<property> <name>hbase.bucketcache.combinedcache.enabled</name> <value>true</value> </property> <property> <name>hbase.bucketcache.ioengine</name> <value>offheap</value> #同時做爲master的rs要用heap </property> <property> <name>hbase.bucketcache.size</name> <value>50176</value> #單位MB。這個值至少要比bucketcache小1G,做爲master的rs用heap,那麼這裏要填<1的值做爲從heap中分配給bucketcache的百分比 </property> <property> <name>hbase.regionserver.global.memstore.size</name> <value>0.60</value> #heap減少了,那麼heap中用於memstore的百分比要增大才能保證用於memstore的內存和原來同樣 </property> <property> <name>hfile.block.cache.size</nname> <value>0.20</value> #使用了bucketcache做爲blockcache的一部分,那麼heap中用於blockcache的百分比能夠減少 </property>
hbase-env.sh
export HBASE_REGIONSERVER_OPTS="-XX:+UseG1GC -Xms30g –Xmx30g -XX:MaxDirectMemorySize=50g
知己知彼方能百戰不殆,在HBase羣集的運行過程當中,咱們須要瞭解HBase實際狀況下的讀寫內存使用,才能最大化的對配置作出最加的調整,接下來講下如何查詢HBase運行中讀寫內存使用狀況
Jmx查詢
http://xxxxxxxx.hadoop.db.com:11111/jmx?qry=Hadoop:service=HBase,name=RegionServer,sub=Server
memStoreSize表明RegionServer中全部HRegion中的memstore大小的總和,單位是Byte。該值的變化,能夠反應出一個RegionServer上寫請求的負載情況,能夠觀察memstoreSize的變化率,若是在單位時間內變化比較抖動,能夠近似認爲寫操做頻繁。
blockCacheFree表明block cache中空閒的內存大小。計算方法爲:getMaxSize() – getCurrentSize(),單位是Byte,該值反映出當前BlockCache中還有多少空間能夠被利用。
blockCacheSize表明當前使用的blockCache的大小。BlockCache. getCurrentSize(),單位是Byte,該值反映出BlockCache的使用情況。
以單臺region server配置爲例
配置項 | 配置值 | 內存分配值 | 實際使用量 |
---|---|---|---|
HBASE_REGIONSERVER_OPTS | -Xms75g –Xmx75g | 75g | 75g |
hbase.regionserver.global.memstore.size | 0.22 | 80g*0.22 = 17.6g | 10800044400/1024/1024/1024 ≈ 10G |
hfile.block.cache.size | 0.22 | 80g*0.22 = 17.6g | 16763937528 /1024/1024/1024 ≈ 15.6G 952802568 /1024/1024/1024 ≈ 0.9G |
結合單臺regionserver 的配置來看,讀寫緩存都有必定空閒空間,這種狀況下能夠下降heap size來減小gc的次數和時長,而後咱們還須要以羣集全部region server的數據來判斷該集羣的配置是否合理,若是存在讀寫不均衡和熱點狀況都會影響不一樣region間的緩存大小。
一張數據表由一個或者多個region 組成,在單個region中每一個columnfamily組成一個store,在每一個store中由一個memstore和多個storefile組成,以下圖所示
HBase是基於LSM-Tree數據結構的,爲了提高寫入性能,全部數據寫入操做都會先寫入memstore中(同時會順序寫入WAL),達到指定大小後會對memstore中的數據作次排序後在批量flush磁盤中,此外新寫入的數據有較大機率被讀取到,所以HBase在讀取數據時首先檢查memstore中是否有數據緩存,未命中的狀況下再去找讀緩存,可見memstore不管對於HBase的寫入和讀取性能都相當重要,而其中memstore flush操做又是memstore最核心的操做。
操做級別 | 觸發條件 | 影響度 |
---|---|---|
memstore級別 | 當region中任意一個memstore的大小達到了上限 即>hbase.hregion.memstore.flush.size = 256mb |
小,短暫阻塞寫 |
region級別 | 當region中全部的memstore的大小達到了上限 即>hbase.hregion.memstore.block.multiplier * hbase.hregion.memstore.flush.size = 8 * 256mb |
小,短暫阻塞寫 |
regionserver級別 | 當一個regionserver中全部memstore的大小達到了上限 即> hbase.regionserver.global.memstore.size * heap_size = 0.22*75g |
大,阻塞regionserver上的全部寫請求且時間較長 |
regionserver中WAL Log數量達到上限 | > hbase.regionserver.maxlogs = 256 系統會選取最先的一個 WAL Log對應的一個或多個region進行flush |
小,短暫阻塞寫 |
按期刷新 | > hbase.regionserver.optionalcacheflushinterval = 3600000 | 小,短暫阻塞寫 |
手動刷新 | 用戶能夠經過shell命令flush table 或者flush region name分別對一個表或者一個region進行flush | 小,短暫阻塞寫 |
從memstore flush的動做來看,對業務影響最大是regionserver級別的flush操做,假設每一個memstore大小爲256mb,每一個region有兩個cf,整個regionserver上有100個region,根據計算可知,總消耗內存 = 256mb2100 = 51.2g >> 0.40*80g = 32g ,很顯然這樣的設置狀況下,很容易觸發region server級別的flush操做,對用戶影響較大。
根據如上分析,memstore的設置大小不只取決於讀寫的比例,也要根據業務的region數量合理分配memstore大小,一樣的咱們對每臺regionserver上region的數量及每張表cf的數量上的控制也能達到理想的效果。
heap模式分配內存會調用byteBuffer.allocate方法,從JVM提供的heap區分配。
內存分配時heap模式須要首先從操做系統分配內存再拷貝到JVM heap,相比offheap直接從操做系統分配內存更耗時,但反之讀取緩存時heap模式能夠從JVM heap中直接讀取比較快。
offheap模式會調用byteBuffer.allocateDirect方法,直接從操做系統分配,由於內存屬於操做系統,因此基本不會產生CMS GC,也就在任何狀況下都不會由於內存碎片致使觸發Full GC。
內存分配時offheap直接從操做系統分配內存比較快,但反之讀取時offheap模式須要首先從操做系統拷貝到JVM heap再讀取,比較費時。
file使用Fussion-IO或者SSD等做爲存儲介質,相比昂貴的內存,這樣能夠提供更大的存儲容量。
使用堆外內存,能夠將大部分BlockCache讀緩存遷入BucketCache,減小jvm heap的size,能夠減小GC發生的頻次及每次GC時的耗時
BucketCache沒有使用JVM 內存管理算法來管理緩存,而是本身對內存進行管理,所以其自己不會由於出現大量碎片致使Full GC的狀況發生。
讀取data block時,須要將off heap的內存塊拷貝到jvm heap在讀取,比較費時,對讀性能敏感用戶不太合適。
對於讀多寫少且對讀性能要求不高的業務場景,offheap模式可以有效的減小gc帶來的影響,線上的vac集羣在開啓offheap模式後,GC頻次和耗時都能有效下降,可是由於bucketcache 讀的性能的問題達不到要求而回退到heap模式。
Hbase服務是基於JVM的,其中對服務可用性最大的挑戰是jvm執行full gc操做,此時會致使jvm暫停服務,這個時候,hbase上面全部的讀寫操做將會被客戶端納入隊列中排隊,一直等到jvm完成gc操做, 服務在遇到full gc操做時會有以下影響
如何避免和預防GC超時的不良影響,咱們須要對JVM的參數進行優化
hbase-env.sh
配置項 | 重要參數詳解 |
---|---|
export HBASE_HEAPSIZE=4096 | HBase 全部實例包括Master和RegionServer佔用內存的大小,不過通常用Master和RegionServer專有參數來分別設定他們的內存大小,推薦值給到4096 |
export HBASE_MASTER_OPTS=" -Xms8g -Xmx8g -Xmn1g -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70" |
Master專有的啓動參數,Xms、Xmx、Xmn分別對應初始堆、最大堆及新生代大小 Master小堆,新生代用並行回收器、老年代用併發回收器,另外配置了CMSInitiatingOccupancyFraction,當老年代內存使用率超過70%就開始執行CMS GC,減小GC時間,Master任務比較輕,通常設置4g、8g左右,具體按照羣集大小評估 |
export HBASE_REGIONSERVER_OPTS="-XX:+UseG1GC -Xms75g –Xmx75g -XX:InitiatingHeapOccupancyPercent=83 -XX:G1HeapRegionSize=32M -XX:ParallelGCThreads=28 -XX:ConcGCThreads=20 -XX:+UnlockExperimentalVMOptions -XX:G1NewSizePercent=8 -XX:G1HeapWastePercent=10 -XX:MaxGCPauseMillis=80 -XX:G1MixedGCCountTarget=16 -XX:MaxTenuringThreshold=1 -XX:G1OldCSetRegionThresholdPercent=8 -XX:+ParallelRefProcEnabled -XX:-ResizePLAB -XX:+PerfDisableSharedMem -XX:-OmitStackTraceInFastThrow -XX:+PrintFlagsFinal -verbose:gc -XX:+PrintGC -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintAdaptiveSizePolicy -XX:+PrintGCDetails -XX:+PrintGCApplicationStoppedTime -XX:+PrintTenuringDistribution -XX:+PrintReferenceGC -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=100M Xloggc:${HBASE_LOG_DIR}/gc-regionserver$(hostname)-`date +'%Y%m%d%H%M'`.log -Dcom.sun.management.jmxremote.port=10102 $HBASE_JMX_BASE" |
RegionServer專有的啓動參數,RegionServer大堆,採用G1回收器,G1會把堆內存劃分爲多個Region,對各個Region進行單獨的GC,最大限度避免Full GC及其影響初始堆及最大堆設置爲最大物理內存的2/3,128G/3*2 ≈80G,在某些度寫緩存比較小的集羣,能夠近一步縮小。InitiatingHeapOccupancyPercent表明了堆佔用了多少比例的時候觸發MixGC,默認佔用率是整個 Java 堆的45%,改參數的設定取決於IHOP > MemstoreSize%+WriteCache%+10~20%,避免過早的MixedGC中,有大量數據進來致使Full GCG1HeapRegionSize 堆中每一個region的大小,取值範圍【1M..32M】2^n,目標是根據最小的 Java 堆大小劃分出約 2048 個區域,即heap size / G1HeapRegionSize = 2048 regionsParallelGCThreads設置垃圾收集器並行階段的線程數量,STW階段工做的GC線程數,8+(logical processors-8)(5/8)ConcGCThreads併發垃圾收集器使用的線程數量,非STW期間的GC線程數,能夠嘗試調大些,能更快的完成GC,避免進入STW階段,可是這也使應用所佔的線程數減小,會對吞吐量有必定影響G1NewSizePercent新生代佔堆的最小比例,增長新生代大小會增長GC次數,可是會減小GC的時間,建議設置5/8對應負載normal/heavy集羣G1HeapWastePercent觸發Mixed GC的堆垃圾佔比,默認值5G1MixedGCCountTarget一個週期內觸發Mixed GC最大次數,默認值8這兩個參數互爲增長到10/16,能夠有效的減小1S+ Mixed GC STW timesMaxGCPauseMillis 垃圾回收的最長暫停時間,默認200ms,若是GC時間超長,那麼會逐漸減小GC時回收的區域,以此來靠近此閾值,通常來講,按照羣集的重要性 50/80/200來設置verbose:gc在日誌中輸出GC狀況 |