通常安裝好的HBase集羣,默認配置是給Master和RegionServer 1G的內存,而Memstore默認佔0.4,也就是400MB。顯然RegionServer給的1G真的太少了。java
export HBASE_MASTER_OPTS="$HBASE_MASTER_OPTS -Xms2g -Xmx2g" export HBASE_REGIONSERVER_OPTS="$HBASE_REGIONSERVER_OPTS -Xms8g -Xmx8g"
這裏只是舉例,並非全部的集羣都是這麼配置。
==要牢記至少留10%的內存給操做系統來進行必要的操做==算法
如何給出一個合理的JVM 內存大小設置,舉一個ambari官方提供的例子吧。windows
好比你如今有一臺16GB的機器,上面有MapReduce服務、 RegionServer和DataNode(這三位通常都是裝在一塊兒的),那麼建議按 照以下配置設置內存:緩存
若是同時運行MapReduce的話,RegionServer將是除了MapReduce之外使用內存最大的服務。若是沒有MapReduce的話,RegionServer能夠調整到大概一半的服務器內存。服務器
因爲數據都是在RegionServer裏面的,Master只是作一些管理操做,因此通常內存問題都出在RegionServer上。併發
JVM提供了4種GC回收器:性能
通常會採起兩種組合方案測試
export HBASE_REGIONSERVER_OPTS="$HBASE_REGIONSERVER_OPTS -Xms8g -Xmx8g -XX:+UseParNewGC -XX:+UseConMarkSweepGC"
優化
export HBASE_REGIONSERVER_OPTS="$HBASE_REGIONSERVER_OPTS -Xms8g -Xmx8g -XX:+UseG1GC -XX:MaxGCPauseMillis=100"
spa
怎麼選擇呢?
通常內存很大(32~64G)的時候,纔會去考慮用G1GC方案。
若是你的內存小於4G,乖乖選擇第一種方案吧。
若是你的內存(4~32G)之間,你須要自行測試下兩種方案,孰強孰弱靠實踐。測試的時候記得加上命令-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintAdaptiveSizePolicy
HBase本身實現了一套以Memstore爲最小單元的內存管理機制,稱爲 MSLAB(Memstore-Local Allocation Buffers)
跟MSLAB相關的參數是:
在HBase2.0版本中,爲了實現更高的寫入吞吐和更低的延遲,社區團隊對MemStore作了更細粒度的設計。這裏,主要指的就是In Memory Compaction。
開啓的條件也很簡單。
hbase.hregion.compacting.memstore.type=BASIC # 可選擇NONE/BASIC/EAGER
具體這裏不介紹了。
Region的拆分分爲自動拆分和手動拆分。自動拆分能夠採用不一樣的策略。
0.94版本的策略方案
hbase.hregion.max.filesize
經過該參數設定單個Region的大小,超過這個閾值就會拆分爲兩個。
文件尺寸限制是動態的,依賴如下公式來計算
Math.min(tableRegionCount^3 * initialSize, defaultRegionMaxFileSize)
假如hbase.hregion.memstore.flush.size定義爲128MB,那麼文件 尺寸的上限增加將是這樣:
除了簡單粗暴地根據大小來拆分,咱們還能夠本身定義拆分點。 KeyPrefixRegionSplitPolicy 是 IncreasingToUpperBoundRegionSplitPolicy的子類,在前者的基礎上增長了對拆分點(splitPoint,拆分點就是Region被拆分處的rowkey)的定義。它保證了有相同前綴的rowkey不會被拆分到兩個不一樣的Region裏面。這個策略用到的參數是KeyPrefixRegionSplitPolicy.prefix_length rowkey:前綴長度
那麼它與IncreasingToUpperBoundRegionSplitPolicy區別,用兩張圖來看。
默認策略爲
KeyPrefixRegionSplitPolicy策略
若是你的前綴劃分的比較細,你的查詢就比較容易發生跨Region查詢的狀況,此時採用KeyPrefixRegionSplitPolicy較好。
因此這個策略適用的場景是:
該策略也是繼承自IncreasingToUpperBoundRegionSplitPolicy,它也是根據你的rowkey前綴來進行切分的。惟一的不一樣就是: KeyPrefixRegionSplitPolicy是根據rowkey的固定前幾位字符來進行判斷,而DelimitedKeyPrefixRegionSplitPolicy是根據分隔符來判斷的。在有些系統中rowkey的前綴可能不必定都是定長的。
使用這個策略須要在表定義中加入如下屬性:
DelimitedKeyPrefixRegionSplitPolicy.delimiter:前綴分隔符
好比你定義了前綴分隔符爲_,那麼host1_001和host12_999的前綴就分別是host1和host12。
若是你的系統經常會出現熱點Region,而你對性能有很高的追求, 那麼這種策略可能會比較適合你。它會經過拆分熱點Region來緩解熱點 Region的壓力,可是根據熱點來拆分Region也會帶來不少不肯定性因 素,由於你也不知道下一個被拆分的Region是哪一個。
這種策略就是Region永不自動拆分。
若是你事先就知道這個Table應該按 怎樣的策略來拆分Region的話,你也能夠事先定義拆分點 (SplitPoint)。所謂拆分點就是拆分處的rowkey,好比你能夠按26個 字母來定義25個拆分點,這樣數據一到HBase就會被分配到各自所屬的 Region裏面。這時候咱們就能夠把自動拆分關掉,只用手動拆分。
手動拆分有兩種狀況:預拆分(pre-splitting)和強制拆分 (forced splits)。
一開始能夠先定義拆分點,可是當數據開始工做起來後會出現熱點 不均的狀況,因此推薦的方法是:
==建議:不要關閉自動拆分。==
Region的拆分對性能的影響仍是很大的,默認的策略已經適用於大 多數狀況。若是要調整,儘可能不要調整到特別不適合你的策略
一個RegionServer只有一個BlockCache。
BlockCache的工做原理:讀請求到HBase以後先嚐試查詢BlockCache,若是獲取不到就去HFile(StoreFile)和Memstore中去獲取。若是獲取到了則在返回數據的同時把Block塊緩存到BlockCache中。它默認是開啓的。
若是你想讓某個列簇不使用BlockCache,能夠經過如下命令關閉它。
alter 'testTable', CONFIGURATION=>{NAME => 'cf',BLOCKCACHE=>'false'}
BlockCache的實現方案有
在0.92版本 以前只有這種BlockCache的實現方案。LRU就是Least Recently Used, 即近期最少使用算法的縮寫。讀出來的block會被放到BlockCache中待 下次查詢使用。當緩存滿了的時候,會根據LRU的算法來淘汰block。 LRUBlockCache被分爲三個區域,
看起來是否是很像JVM的新生代、年老代、永久代?沒錯,這個方案就是模擬JVM的代設計而作的。
SlabCache實際測試起來對Full GC的改善很小,因此這個方案最後被廢棄了。不過它被廢棄還有一個更大的緣由,這就是有另外一個更好的Cache方案產生了,也用到了堆外內存,它就是BucketCache。
Bucket Cache默認也是開啓的,若是要關閉的話
alter 'testTable', CONFIGURATION=>{CACHE_DATA_IN_L1 => 'true'}
它的配置項:
在SlabCache的時代,SlabCache,是跟LRUCache一塊兒使用的,每一 個Block被加載出來都是緩存兩份,一份在SlabCache一份在LRUCache, 這種模式稱之爲DoubleBlockCache。讀取的時候LRUCache做爲L1層緩存 (一級緩存),把SlabCache做爲L2層緩存(二級緩存)。
在BucketCache的時代,也不是單純地使用BucketCache,可是這回 不是一二級緩存的結合;而是另外一種模式,叫組合模式 (CombinedBlockCahce)。具體地說就是把不一樣類型的Block分別放到 LRUCache和BucketCache中。
Index Block和Bloom Block會被放到LRUCache中。Data Block被直 接放到BucketCache中,因此數據會去LRUCache查詢一下,而後再去 BucketCache中查詢真正的數據。其實這種實現是一種更合理的二級緩 存,數據從一級緩存到二級緩存最後到硬盤,數據是從小到大,存儲介質也是由快到慢。考慮到成本和性能的組合,比較合理的介質是: LRUCache使用內存->BuckectCache使用SSD->HFile使用機械硬盤。
關於LRUBlockCache和BucketCache單獨使用誰比較強,曾經有人作 過一個測試。
從總體上說LRUCache的性能好於BucketCache,但因爲Full GC的存在,在某些時刻JVM會中止響應,形成服務不可用。因此適當的搭配 BucketCache能夠緩解這個問題。
合併分爲兩種操做:
從舊到新地掃描HFile文件,當掃描到某個文件,該文件知足如下條件:
該文件大小 < 比它更新的全部文件的大小總和 * hbase.store.compation.ratio(默認1.2)
實際狀況下的RatioBasedCompactionPolicy算法效果不好,常常引 發大面積的合併,而合併就不能寫入數據,常常由於合併而影響IO。所 以HBase在0.96版本以後修改了合併算法。
0.96版本以後提出了ExploringCompactionPolicy算法,而且把該 算法做爲了默認算法。
算法變動爲
該文件大小 < (全部文件大小總和 - 該文件大小) * hbase.store.compation.ratio(默認1.2)
若是該文件大小小於最小合併大小(minCompactSize),則連上面那個公式都不須要套用,直接進入待合併列表。最小合併大小的配置項:hbase.hstore.compaction.min.size。若是沒設定該配置項,則使用hbase.hregion.memstore.flush.size。
被挑選的文件必須能經過以上提到的篩選條件,而且組合內含有的文件數必須大於hbase.hstore.compaction.min,小於 hbase.hstore.compaction.max。
文件太少了不必合併,還浪費資源;文件太多了太消耗資源,怕 機器受不了。
挑選完組合後,比較哪一個文件組合包含的文件更多,就合併哪一個組 合。若是出現平局,就挑選那個文件尺寸總和更小的組合。
這個合併算法實際上是最簡單的合併算法。嚴格地說它都不算是一種合併算法,是一種刪除策略。
FIFOCompactionPolicy策略在合併時會跳過含有未過時數據的 HFile,直接刪除全部單元格都過時的塊。最終的效果是:
這個策略不能用於什麼狀況
DateTieredCompactionPolicy解決的是一個基本的問題:最新的數據最 有可能被讀到。
配置項
配置項好像很複雜的樣子,舉個例子畫個圖就清楚了。
假設基本窗口寬度 (hbase.hstore.compaction.date.tiered.base.window.millis) = 1。 最小合併數量(hbase.hstore.compaction.min) = 3。 層次增加倍數 (hbase.hstore.compaction.date.tiered.windows.per.tier) = 2。
這個策略很是適用於什麼場景
這個策略比較適用於什麼場景
這個策略不適用於什麼場景
該策略在讀取方面穩定。
那麼什麼場景適合用StripeCompactionPolicy
請詳細地看各類策略的適合場景,並根據場景選擇策略。