hbase實踐之寫流程拾遺

keyvalue

KeyValue中包含了豐富的自我描述信息:
image併發

KeyValue是支撐」稀疏矩陣」設計的一個關鍵點:一些Key相同的任意數量的獨立KeyValue就能夠構成一行數據。但這種設計帶來的一個顯而易見的缺點:每個KeyValue所攜帶的自我描述信息,會帶來顯著的數據膨脹。mvc

爲何rowkey不能太長?columnfamily、qualifiter儘可能短?app

image

行級事務模型

寫寫併發控制

包括單行、批量多行。設計

  • 單行:行鎖
  • 多行:兩階段鎖協議,即:

(1) 獲取全部待寫入(更新)行記錄的行鎖日誌

(2) 開始執行寫入(更新)操做server

(3) 寫入完成以後再統一釋放全部行記錄的行鎖blog

讀寫併發控制:MVCC

Mutil Version Concurrent Control。HBase中MVCC機制實現主要分爲兩步:事務

(1) 爲每個寫(更新)事務分配一個Region級別自增的序列號ip

(2) 爲每個讀請求分配一個已完成的最大寫事務序列號ci

MVCC的精髓是寫入的時候分配遞增版本信息(SequenceId),讀取的時候分配惟一的版本用於讀取可見,比之大的版本不可見。這裏須要注意版本必須遞增,並且版本遞增的範圍必定程度上決定了事務是什麼事務,好比HBase是Region級別的遞增版本,那麼事務就是region級別事務。

非必須狀況,不要使用行鎖。

sequenceId

爲何要有sequenceId?

  1. 先寫HLog,再寫memstore,兩個地方的數據是一致的,二者如何一一對應?一一對應後,日誌可刪除(由於只能保留有限日誌)。
  2. HLog日誌如何刪除?HLog只能保存必定數量的日誌,若是刪除日誌文件,先刪除誰? 先刪除年齡最老的日誌文件,則其sequenceId最小。若是這些數據沒有落盤,就能夠強制對其執行flush,以後就能夠將HLog刪除。
  3. RegionServer宕機,memsotre中數據丟失,數據從哪裏開始恢復?

本質問題:mestore、Hlog中的數據是同一份,他們須要同一個標識。

  1. 讀寫併發控制
  • HLog文件的基本結構
    image

<logseq#-for-entire-txn>:<-1, 3, , , >

The -1 marker is just a special way of being backward compatible with an old HLog which would have contained a single . -1只是一個標誌, 是爲了對舊版本兼容.

問題一:HLog在何時能夠過時回收?HLog在何時能夠過時回收?

RegionServer會爲每一個Region維護了一個變量oldestUnflushedSequenceId(其實是爲每一個Store,爲了方便講解,此處暫且認爲是Region,不影響原理),表示這個Region最先的還未落盤的seqid ,即這個seqid以前的全部數據都已經落盤。

下圖是flush過程當中oldestUnflushedSequenceId變量變化的示意圖,初始時爲null,假設在某一時刻階段二RegionA(紅色方框)要執行flush,中間HLog中sequenceId爲1~4對應的數據將會落盤,在執行flush以前,HBase會append一個空的Entry到HLog,僅爲獲取下一個sequenceId(5),並將這個sequenceId賦給OldestUnflushedSequenceId-RegionA。如圖中第三階段OldestUnflushedSequenceId-RegionA指向sequenceId爲5的Entry。

image

image

場景一中右側HLog還有未落盤的數據(sequenceid=5還未落盤),所以不能刪除;而場景二中右側HLog的全部數據都已經落盤,因此這個HLog理論上就已經能夠被刪除回收。

問題二:HLog數量超過閾值(maxlogs)以後刪除最先HLog,應該強制刷新哪些Region?

image

HLog日誌文件超過閾值,會刪除最老的,根據OldestUnflushedSequenceId,若是該日誌中有數據未寫磁盤,則強制刷寫磁盤,而後將該日誌文件刪除。

問題三:RegionServer宕機恢復replay日誌時哪些WALEntry須要被回放,哪些會被skip?

理論上來講只須要回放Memstore中沒有落地的數據對應的WALEntry,已經落地數據對應的WALEntry能夠skip。可問題是RegionServer已經宕機了,<region, oldestUnflushedSequenceId> 對應信息確定沒有了,如何是好?想辦法持久化唄,上文分析oldestUnflushedSequenceId變量是flush時產生的一個變量,這個變量徹底能夠以flush的時候以元數據的形式寫到HFile中(代碼見下圖):

image

到目前爲止,上面全部分析都基於一個事實:hbase中flush操做是region級別操做,即每次執行flush都須要整個region中的全部store全都執行flush。

Per-CF Flush

map<region, map<store, oldestUnflushedSequenceId>>

RS宕機與恢復

image

image

由HMaster來管理並切分日誌==>RegionServer切分日誌(小文件多)==>RegionServer切分日誌後,直接在Region-Buffer中回放。

Region 切分

Region切分觸發策略

  1. ConstantSizeRegionSplitPolicy
  2. IncreasingToUpperBoundRegionSplitPolicy:(#regions) * (#regions) * (#regions) * flush size * 2

在大集羣條件下對於不少大表來講表現很優秀,但並不完美,這種策略下不少小表會在大集羣中產生大量小region,分散在整個集羣中。並且在發生region遷移時也可能會觸發region分裂。

  1. SteppingSplitPolicy:若是region個數等於1,切分閾值爲flush size * 2,不然爲MaxRegionFileSize。

切分本質

image

雖然產生2個子Region,但仍是指向原來的HFile文件。只有major compaction時,父region的數據纔會遷移到子region目錄。

參考文獻

相關文章
相關標籤/搜索