Hbase拆分與合並


 

Region的拆分

隨着大合並的增多,一個region越來越大,造成數據的存儲不平衡,訪問速度也會變慢。

  • 所以,當region達到一定大小(默認10G),region會先下線,一分為二,分為兩個region,R1,R2.
  • Hmaster會將R2遷移到其他的regionserver中。底層的Hfile指向新的region2
  • 更新元數據信息region1 region2到HBASE:meta表

Region的合並

  • Region的合並不是為了性能, 而是出於維護的目的 .
  • 比如刪除了大量的數據 ,這個時候每個Region都變得很小 ,存儲多個Region就浪費了 ,這個時候可以把Region合並起來,進而可以減少一些Region服務器節點

Region合並有兩種方式

  • 冷合並
  • 熱合並

Region冷合並

  • 執行合並前,需要先關閉hbase集群
  • 通過hbase +org.apache.hadoop.hbase.util.Merge類 + table name全名合並
  • 不需要進入hbase shell,直接執行
hbase org.apache.hadoop.hbase.util.Merge person 
person,,1593953711622.dcd1823dc1cc11ba251fe7e18e747a75. 
person,1000,1593953711622.ca647144d51cd76f01909801d070bf6f.
  • 1
  • 2
  • 3

在這里插入圖片描述
合並前
在這里插入圖片描述
合並后:
在這里插入圖片描述

Region熱合並

  • 不需要關閉hbase集群,在線進行合並

  • 與冷合並不同的是,online_merge的傳參是Region的hash值,而Region的hash值就是Region名稱的最后那段在兩個.之間的字符串部分。

  • 需求:需要把test表中的2個region數據進行合並:
    student,1593954415190.098539361430261d4c02cf78c0134a04.
    student,aa,1593954415190.f9650b81405e95bf1d32bdf5c137192a.

  • 需要進入hbase shell:

merge_region '098539361430261d4c02cf78c0134a04','f9650b81405e95bf1d32bdf5c137192a' 
  • 1

合並前:
在這里插入圖片描述
合並后:
在這里插入圖片描述

 

 

1 Region拆分

一個Region代表一個表的一段Rowkey的數據集合,當Region太大,Master會將其拆分。Region太大會導致讀取效率太低,遍歷時間太長,通過將大數據拆分到不同機器上,分別查詢再聚合,Hbase也被人稱為“一個會自動分片的數據庫”。
Region可以手動和自動拆分。

1.1 Region自動拆分

1.1.1 ConstantSizeRegionSplitPolicy

固定大小拆分策略,0.94版本之前的唯一拆分方法,如果單個Region大小超過了閥值那么就拆分為兩個Region,這種策略使得急群眾的Region大小很平均。唯一的參數是(hbase-site.xml):

hbase.hregion.max.filesize:region最大大小,默認為10GB
<property> <name>hbase.hregion.max.filesize</name> <value>10 * 1024 * 1024 * 1024</value> </property> 

1.1.2 IncreasingToUpperBoundRegionSplitPolicy

動態限制拆分策略,是新版本的默認策略。有的數據庫文件增長是翻倍的數據量,128M,256M,512M……,該策略與之類似,限制是動態的,計算公式為:

Math.min(tableRegionsCount^3 * initialSize,defaultRegionMaxFileSize) 
  • tableRegionCount:當前表在所有RegionServer上擁有的所有的Region數量的總和
  • initialSize:如果定義了hbase.increasing.policy.initial.size,則使用該值,否則用memstore刷寫值得2倍,即hbase.hregion.memstore.flush.size*2。
  • deffaultRegionmaxFileSize:ConstantSizeRegionSplitPolicy所用到的配置項,也就是Region的最大大小
  • Math.min:取這兩個數值的最小值

當初始hbase.hregion.memstore.flush.size定義為128M,過程為:

  1. 剛開始只有一個Region,上限為1^31282=256M
  2. 當有2個Region,上限為2^31282=2048M
  3. 當有3個Region,上限為3^31282=6912M
  4. 以此類推當有4個Region時候,為16G,上限達到了10GB,最大值就保持在了10G,Region數量再增加也不會增加上限

涉及到的相關配置有(hbase-site.xml中配置):

#動態限制拆分策略的初始化大小
hbase.increasing.policy.initial.size #memstore最大刷寫值 hbase.hregion.memstore.flush.size #固定大小拆分策略定義的最大Region大小 hbase.hregion.max.filesize 

1.1.3 KeyPrefixRegionSplitPolicy

固定長度前綴拆分策略,是IncreasingToUpperBoundRegionSplitPolicy的子類,在其基礎上增加了對拆分點(splitPoint,拆分點就是Region被拆分出的RwoKey)的定義,保證了有相同前綴的key不會被拆分到兩個不同的Region中。該策略會根據KeyPrefixRegionSplitPolicy.prefix_lenth所定義的長度來截取rowkey作為分組的依據。
當所有數據只有一兩個前綴那么keyPrefixRegionSplitPolicy就不太有效,采用默認比較好,但是前綴如果划分比較細,查詢容易發生跨Region查詢的情況,這時候就比較實用。所以適合實用的場景有:

  • 數據有多種前綴
  • 查詢多是針對前綴,比較少跨越多個前綴來查詢數據

涉及到的配置參數有:

KeyPrefixRegionSplitPolicy.prefix_length rowkey:前綴長度 

1.1.4 DelimitedKeyPrefixRegionSplitPolicy

分隔符前綴拆分策略,也是IncreasingToUpperBoundRegionSplitPolicy的子類,按照分隔符來判斷是否進行拆分,比如定義了前綴分隔符為_,那么rowkey為host1_aaaaabbbb,host2_sjfijts,這兩個數據會被拆分到不同的Region中。涉及到的配置參數有:

DelimitedKeyPrefixRegionSplitPolicy.delimiter:前綴分隔符 

1.1.5 BusyRegionSplitPolicy

熱點拆分策略,這是唯一考慮到熱點數據的拆分策略,如果數據庫中的Region某些短時間內被訪問很頻繁,承載了很大壓力,就是熱點Region,涉及到的配置參數有:

hbase.busy.policy.blockedRequests:請求阻塞率,即請求被阻塞的嚴重程度,范圍0.0-1.0,默認0.2,20%請求被阻塞 hbase.busy.policy.minAge:拆分最小年齡,當Region大於這個值才進行拆分,防止判斷是否要拆分時候出現短時間的訪問頻率波分導致沒必要拆分的region被拆分。而短時前的波峰可能會快就會恢復到正常水平,單位毫秒,默認值600000,10分鍾。 hbase.busy.policy.aggWindow:計算是否繁忙的時間窗口,單位毫秒,默認值300000,5分鍾,用以控制計算的評率 

上訴三個配置項都是用於計算Region是否是熱點Region的配置項,計算方法為:

  • 當前時間 - 上次檢測時間 >=hbase.busy.policy.aggWindow,則繼續進行下一步計算
  • 這段時間被阻塞的請求/這段時間的總請求=請求的被阻塞率(aggBlockedRate)
  • 若aggBlockedRate > hbase.busy.policy.blockedRequests,那么該Region為繁忙

如果對性能要求比較高,該策略比較有效,但是因為Region拆分的不確定性,會帶來很多不確定因素。

1.1.6 DisabledRegionSplitPolicy

手動拆分策略,其實就是上訴所有的策略都失效,不管如何判斷,都會返回不拆分。
自動拆分策略都是數據最開始寫入一個Region,之后可能會發生數據大量寫入的同時還進行拆分,如果我們知道如果拆分Region,我們就可以提前定義拆分點,數據就會直接分配到各自所需的Region,手動拆分有如下良兩種:

1.2 手動拆分

1.2.1 pre-splitting Region預拆分

就是在建表的時候就定義好拆分點的算法,使用org.apache.hadoop.hbase.util.RegionSplitter類來創建表,並傳入拆分點算法,就可以在建表同事定義拆分點算法。比如;

hbase org.apache.hadoop.hbase.util.RegionSplitter table_name HexStringSplit -c 10 -f mycf HexStringSplit:指定的拆分點算法 -c:要拆分的Region數量 -f:要建立的列族名稱 #會建立10個固定的Region,使用如下語句查看創建的Region scan 'hbase:meta',{STARTROW=>'table_name',LIMIT => 10} 

具體的拆分點算法有:

1.2.1.1 HexStringSplit

ASCII碼預拆分策略,只需要傳入一個要拆分的Region的數量,HexStringSplit會將數據從“00000000”到“FFFFFFFF”之間的數據長度按照n等分之后算出每一段的其實rowkey和結束rowkey,以此作為拆分點。

1.2.1.2 UniformSplit

字節碼預拆分策略,與ASCII碼預拆分不同的是,起始結束不是Sting而是byte[]

  • 起始rowkey是ArrayUtils.EMPTY_BYTE_ARRAY
  • 結束rowkey是new byte[]{xFF,xFF,xFF,xFF,xFF,xFF,xFF,xFF}

最后調用Bytes.split方法把其實rowkey到結束rowkey之間的長度n等分,然后取每一段的起始和結束作為拆分點
默認預拆分算法只有這兩個,我們也可以通過實現SplitAlgorithm接口實現自己的拆分算法,或者干脆手動定出拆分點。

1.2.2 手動制定拆分點(屬於預拆分)

只需要在建表的時候跟上SPLITS參數:

create 'test_split2','mycf2','mysf2',SPLITS=>['AAA','BBB','CCC'] 

1.2.3 強制拆分

其實這個才是實際意義上的手動拆分,通過運行命令強制手動拆分(forced splits),調用hbase shell的split方法。

#將表table_name從1000出拆分為兩個Region split 'table_name,c,1476405886999.96dd83893d683','1000' #其他調用方式有: split 'tableName' split 'namespace:tableName' split 'regionName'#format:'tableName,startKey,id' split 'tableName','splitKey' split 'regionName','splitKey' 

1.3 總結

建議開始的時候定義預拆分,導入初始數據,之后使用自動拆分來讓HBase自動管理Region。不要關閉自動拆分。這樣科比避免因為直接使用預拆分導致的熱點Region問題。
盡量使用適合業務的拆分策略,比如不要在時間戳為rowley前綴的情況下還是iyongKeyPrefixRegionSplitPolicy來作為拆分策略,這會導致嚴重的熱點問題。


2 Region合並(Merge)

首先,Region的合並(merge)並不是為了性能考慮而是處於維護的目的被創造出來的。比如刪了大量的數據,導致每個Region都變小了,這個時候合並Region就比較合適了。

2.1 通過Merge類冷合並Region

通過org.apache.hadoop.hbase.util.Merge類來實現,不需要進入hbase shell,直接執行:

hbase org.apache.hadoop.hbase.util.Merge table_name \ table_name,a,147608089478.39erijidsfd8s098fen32j3i8d9. \ table_name,b,148893879502.48jfidnxoskd023843257822j3i. 

就可以實現兩個Region的合並,但是有一個前提,必須保證這兩個Region已經下線,保證HMaster和所有的HRegionServer都停掉,否則會報錯,但是這樣太麻煩了,而且不適合生產使用。

2.2 通過online_merge熱合並Region

與冷合並不同的是,online_merge的傳參是Region的hash值,而Region的hash值就是Region名稱的最后那段在兩個.之間的字符串部分,需要進入hbase shell:

> merge_region '39erijidsfd8s098fen32j3i8d9','48jfidnxoskd023843257822j3i' #通過hbase:meta查看Region合並后的信息 

3 HFile合並(Compact)

MemStore每次刷寫都會生成一個HFile,當HFile變多,回到值讀取數據磁頭尋址緩慢,因為HFile都分散在不同的位置,為了防止尋址動作過多,適當的減少碎片文件,就需要合並HFile。

3.1 HFile的合並策略

合並操作主要是在一個Store里邊找到需要合並的HFile,然后把它們合並起來,合並在大體意義上有兩大類Minor Compation和Major Compaction:

  • Minor Compaction:將Store中多個HFile合並為一個HFile,這個過程中,達到TTL(記錄保留時間)會被移除,但是有墓碑標記的記錄不會被移除,因為墓碑標記可能存儲在不同HFile中,合並可能會跨國部分墓碑標記。這種合並的觸發頻率很高
  • Major Compaction:合並Store中所有的HFile為一個HFile(並不是把一個Region中的HFile合並為一個),這個過程有墓碑標記的幾率會被真正移除,同時超過單元格maxVersion的版本記錄也會被刪除。合並頻率比較低,默認7天執行一次,並且性能消耗非常大,最后手動控制進行合並,防止出現在業務高峰期。

需要注意的是,有資料說只有Major合並才會刪數據,其實Major合並刪除的是帶墓碑標記的,而Minor合並直接就不讀取TTL過期文件,所以也相當於刪除了。

3.1.1 老版本的合並策略(0.96之前)RationBasedCompactionPolicy

基於固定因子的合並策略,從舊到新掃描HFile文件,當掃描到某個文件滿足條件:

該文件大小 < 比它更新的所有文件大小綜合 *hbase.store.compaction.ratio 

就把該HFile和比它更新的所有HFile合並為一個HFile。
但是實際上,Memstore很多情況下會有不同的刷寫情況,所以每次的HFile不一定一樣大,比如最后一次導入數據需要關閉Region,強制刷寫導致數據非常少。實際情況下RatioBasedCompactionPolicy算法效果很差,經常應發大面積合並,合並就不能寫入數據,影響IO。

3.1.2 新版本合並策略 ExploringCompactionPolicy

是新版本的默認算法,不再是強順序遍歷,而是整體遍歷一遍然后綜合考慮,算法模型是:

該文件大小 < (所有文件大小綜合 - 該文件大小) * 比例因子

如果HFile小於minCompactionSize,則不需要套用公式,直接進入待合並列表,如果沒有配置該項,那么使用hbase.hregion.memstore.flush.size。

#合並因子
hbase.store.compaction.ratio #合並策略執行最小的HFile數量 hbase.hstore.compaction.min.size #合並策略執行最大的HFile數量 hbase.hstore.compaction.max.size #memstore刷寫值, hbase.hregion.memstore.flush.size #參與合並最小的HFile大小 minCompactionSize 

所以一個HFile是否進行參與合並:

  • 小於minCompactionSize,直接進入合並列表
  • 大minCompactionSize,用公式決定是否參與合並
  • 窮舉出所有可執行合並列表,要求數量要>hbase.hstore.compaction.min.size,且<=hbase.hstore.compaction.max.size
  • 比較所有組,選出其中數量最多
  • 在數量最多且一樣的組中,選擇總大小最小的一組

3.1.3 FIFOCompactionPolicy

先進先出合並策略,最簡單的合並算法,甚至可以說是一種刪除策略。minor、major合並一定會發生但是頻率不同,但是有時候沒必要執行合並:

  • TTL特別短,比如中間表,只是在計算中間暫存一些數據,很容易出現一整個HFile都過去
  • BlockCache非常大,可以把整個RegionServer上的數據都放進去,就沒必要合並了,因為所有數據都可以走緩存

因為合並會把TTL超時數據刪掉,兩個合並就回導致其實把HFile都刪除了,而FIFO策略在合並時候就會跳過含有未過期數據的HFile,直接刪除所有單元格都過期的塊,所以結果就是過期的快上整個被刪除,而沒過期的完全沒有操作。而過程對CPU、IO完全沒有壓力。但是這個策略不能用於:

  • 表沒有設置TTL,或者TTL=ForEver
  • 表設置了Min_Versions,並且大於0

因為如果設置了min_versions,那么TTL就會失效,芮然達到了TTL時間,但是因為有最小版本數的限制,依舊不能刪除。但是如果手動進行delete依舊可以刪到小於最小版本數,min_versions只能約束TTL,所以FIFO不適用設置了min_versions的情況。

3.1.4 DateTieredCompactionPolicy

日期迭代合並刪除策略,主要考慮了一個比較重要的點,最新的數據可能被讀取的次數是最多的,比如電商中用戶總是會查看最近的訂單;隨着時間的推移,用戶會逐漸減緩對老數據的點擊;非常古老的記錄鮮有人問津。
電商訂單這種數據作為歷史記錄一定沒有TTL,那么FIFO合並策略不合適;單純的看大小進行合並也不太有效,如果把新數據和老數據合並了,反而不好,所以Exploring也不友好。Ratio就更別考慮了,每次合並都卷入最新的HFile。
所以DateTieredCompactionPolicy的特點是:

  • 為了新數據的讀取性能,將新舊文件分開處理,新的和新的合並,舊的和舊的合並
  • 不能只把數據分為新舊兩種,因為讀取頻率是連續的,所以可以分為多個階段,分的越細越好
  • 太早的文件就不合並了,沒什么人讀取,合不合並沒有太大差別,合並了還消耗性能

涉及到的配置項有有:

#初始化時間窗口時長,默認6小時,最新的數據只要在6小時內都會在初始化時間窗口內
hbase.hstore.compaction.date.tiered.base.window.millis # 層次增長倍數,用於分層。越老的時間窗口越長,如果增長倍數是2,那么時間窗口為6、12、24小時,以此類推。如果時間窗口內的HFile數量達到了最小合並數量(hbase.hstore.compaction.min)就執行合並,並不是簡單合並成一個,默認是使用ExploringCompactionPolicy(策略套策略),使用hbase.hstore.compaction.date.tiered.window.policy.class所定義 hbase.hstore.compaction.date.tiered.windows.per.tier #最老的層次時間,如果文件太老超過了該時間定義的范圍(默認天為單位)就直接不合並了。 hbase.hstore.compaction.date.tiered.max.tier.age.millis #最小合並數量 hbase.hstore.compaction.min 

有一個確定就是,如果Store中的某個HFile太老了,但是有沒有超過TTL,且大於了最老層次時間,那么這個HFile在超時被刪除之前都不會被刪除,不會發生Major合並,用戶手動刪除數據也不會真正被刪除,而是一直占用着空間。
其實歸根到底,合並的最終策略是每個時間涌口中的HFile數量達到了最小合並數量,那么就回進行合並。另外,當一個HFile跨了時間線的時候,將其定義為下一個時間窗口(更老的更長的)。
適用場景:

  • 適用於經常讀寫最近數據的系統,專注於新數據
  • 因為哪個缺點的原因可能引發不了Major合並,沒法刪除手動刪除的信息,更適合基本不刪數據的系統
  • 根據時間排序的存儲也適合
  • 如果數據修改頻率較低,只修改最近的數據,也推薦使用
  • 如果數據改動平凡,老數據也修改,經常邊讀邊寫數據,那么就不太適合了。

3.1.5 StripeCompactionPolicy

簡單來說就是將一個Store里邊的數據分為多層,數據從Memstore刷寫到HFile先落到level 0,當level 0大小超過一定的閥值時候會引發一次合並,會將level 0讀取出來插入到level 1的HFile中去,而level 1的塊是根據建委范圍划分的,最早是分為多層的,后來感覺太復雜,將level 0改名為L0,而level 1-N合並成一個層叫做strips層。依舊是按照鍵位來划分塊。
這種策略的好處是:

  • 通過增加L0層,給合並操作增加了一層緩沖,讓合並操作更加緩和;
  • 嚴格按照鍵位來划分Strips,碎玉讀取雖然不能提高太多速度,但是可以提高查詢速度的穩定性,執行scan時候,跨越的HFile數量保持在了一個比較穩定的數值
  • Major合並本來是牽涉到一個store中的所有HFile,現在可以按照子Strip執行了,因為Major合並一直都會存在因為牽涉HFile太多導致的IO不穩定,而該策略一次只是牽涉到一個Strip中的文件,所以克服了IO不穩定的缺點

Stripe合並策略對於讀取的優化要好於寫的優化,所以很難說會提高多少IO性能,最大的好處就是穩定。那么什么場景適合StripeCompactionPolicy呢?

  • Region要足夠大,如果Region小於2GB那么就不適合該策略,因為小Region用strips會細分為多個stripe,反而增加IO負擔
  • RowKey要具有統一的格式,能夠均勻分布,如果使用timestamp來做rowkey,那么數據就沒法均勻分布了,而用26個首字母就比較合適

3.2 HFile合並的吞吐量限制參數

在使用過程中,如果突然發生IO降低,十有八九是發生compaction了,但是compaction又是不可獲取的,所以就可以通過限制compaction的吞吐量來限制其占用的性能。
由於HBase是分布式系統,吞吐量的概念是磁盤IO+網絡IO的籠統概念,因為沒辦法具體判斷哪一個的IO的限制更大,HBase的吞吐量是通過要合並的HFile的文件大小/處理時間得出的。未發生合並之前就沒法測了,只能通過上一次的合並信息進行簡單預測。具體的設置參數有;

#要限制的類型對象的類名,有兩種
    控制合並相關指標:PressureAwareCompactionThroughputController 控制刷寫相關指標:PressureAwareFlushThroughputContoller hbase.regionserver.throughput.controller #當StoreFile數量達到該值,阻塞刷寫動作,默認是7 hbase.hstore.blockingStoreFile #合並張勇吞吐量下限 hbase.hstore.compaction.throughput.lower.bound #合並占用吞吐量上限 hbase.hstore.compaction.throughput.higher.bound 

hbase.hstore.blockingStoreFile的設置比較講究,如果設置不合理,當HFile數量達到該值之后,會導致Memstore占用的內存急劇上升,很快就達到了Memstore寫入上限,導致memstore阻塞,一點都寫不進去。所以Memstore達到阻塞值的時候,先不要急着調大Memstore的阻塞閥值,要綜合考慮HFile的合並阻塞值,可以適當調大,20、30、50都不算多,HFile多,只是讀取性能下降而已,但是達到阻塞值不只是慢的問題了,是直接寫不進去了。

3.2.1 合並/刷寫吞吐量限制機制

HBase會將合並和刷寫總的吞吐量做計算,如果總吞吐量太大,那么進行適當休眠,因為這兩個參數會限制合並時候占用的吞吐量,也會限制刷寫時候占用的吞吐量。保證業務的響應流暢、保障系統的穩定性。限制會區分高峰時段和非高峰時段,通過如下兩個參數:

#每天非高峰的起始時間,取值為0-23的整數 hbase.offpeak.start.hour #每天非高峰的結束時間,取值為0-23的整數 hbase.offpeak.end.hour 

通過設置非高峰,其他時段就是高峰時段了。在非高峰期是不會進行限速,只有在高峰期占用了太大的吞吐量才會休眠,主要看一個閥值:

lowerBound+(upperBound-lowerBound)*pressureRatio
#合並占用吞吐量的下限,取值是10MB/sec lowerBound:hbase.hstore.compaction.throughput.lower.bound #合並占用吞吐量的上限,取值是20MB/sec upperBound:hbase.hstore.compaction.throughput.higher.bound #壓力比,限制合並時候,該參數就是合並壓力(compactionpressure),限制刷寫時候,該參數刷寫壓力(flushPressure),為0-1.0 pressureRatio 

3.2.2 壓力比

壓力比(pressureRatio)越大,代表HFile堆積的越多,或者即將產生越多的HFile,一旦達到HFile的阻塞閥值,那么久無法寫入數據了,所以合並壓力比越大,合並的需求變得迫在眉睫。壓力比越大,吞吐量的閥值越高,意味着合並線程可以占用更多的吞吐量來進行合並。
壓力比有兩種:
合並壓力(compactionPressure):

(storefileCount-minFilesToCompact) / (blockingFileCount-minFilesToCompact)
storefileCount:當前StoreFile數量
minFilesToCompact:單詞合並文件的數量下限,即hbase.hstore.compaction.min blockingFileCount:就是hbase.hstore.blockingStoreFiles 

當前的StoreFile越大,或者阻塞上限越小,合並壓力越大,更可能發生阻塞
刷寫壓力(flusthPressure):

globalMemstoreSize / memstoreLowerLimitSize globalMemstore :當前Msmstore大小 memstoreLowerLimitSize:Memstore刷寫的下限,當全局memstore達到這個內存占用數量的時候就會開始刷寫 

如果當前的Memstore占用內存越大,或者觸發條件越小,越有可能引發刷寫,刷寫后HFile增多,就有可能發生HFile過多阻塞。

3.3合並的具體過程

具體步驟為:

  • 獲取需要合並的HFile列表
  • 由列表創建出StoreFileScanner
  • 把數據從這些HFile中讀出,並放到tmp目錄(臨時文件夾)
  • 用合並后的新HFile來替換合並前的那些HFile

3.2.1 minor Compaction

第一步:獲取需要合並的HFile列表
獲取列表的時候需要排除掉帶鎖的HFile,分為寫鎖(write lock)和讀鎖(read lock),當HFile正在進行如下操作時候會進行上鎖:

  • 用戶正在進行scan查詢->上Region讀鎖(region read lock)
  • Region正在切分(split):此時Region會先關閉,然后上Region寫鎖(region write lock)
  • Region關閉->上region寫鎖(region write lock)
  • Region批量導入->Region寫鎖(region write lock)

第二步:由列表創建出StoreFileScanner
HRegion會創建出一個Scanner,用Scanner讀取所有需要合並的HFile上的數據
第三步:把數據從這些HFile中讀出,並放到tmp(臨時目錄)
HBase會在臨時目錄中創建新的HFile,並把Scanner讀取到的數據放入新的HFile,數據過期(達到了TTL時間)不會被讀出:
第四步:用合並后的HFile來替換合並前的那些HFile
最后用哪個臨時文件夾合並后的新HFile來替換掉之前那些HFile文件,過期的數據由於沒有被讀取出來,所以就永遠消失了。

3.2.2 Major Compaction

HBase中並沒有一種合並策略叫做Major Compaction,Major Compaction目的是增加讀性能,在Minor Compaction的基礎上可以實現刪除掉帶墓碑標記的數據。因為有時候,用戶刪除的數據,墓碑標記和原始數據這兩個KeyValue在不同的HFile上。在Scanner階段,會將所有HFile數據查看一遍,如果數據有墓碑標記,那么就直接不Scan這條數據。
所以之前介紹的每一種合並策略,都有可能升級變為majorCompaction,如果本次Minor Compaction包含了當前Store所有的HFile,並且達到了足夠的時間間隔,則會被升級為Major Compaction。這兩個閥值的配置項為:

  • hbase.hregion.majorcompaction:Major Compaction發生的周期,單位毫秒,默認7天
  • hbase.hregion.majorcompaction.jitter:Major Compaction周期抖動參數,0-1.0,讓MajorCompaction發生時間更加靈活,默認0.5

建議關閉自動Major Compaction,將base.hregion.majorcompaction設置為0.但也不要完全不進行Major Compaction,可以定義一些定時任務在非業務高峰期進行手動調用M按金融Compaction。

3.4 總結

詳細查看各種策略的合適場景,根據場景做策略選擇

  • 如果數據有固定TTL,並且新數據容易被督導,那么選擇DataTieredCompaction
  • 如果沒有TTL或者TTL較大,選擇StripeCompaction
  • FIFOCompaction一般不會被用到,在一些極端情況,比如生存時間特別短的數據。如果想用FIFO,可以先測試一下DataTieredCompaction的性能。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM