HBase 是一個基於 Google BigTable 論文設計的高可靠性、高性能、可伸縮的分佈式存儲系統。 網上關於 HBase 的文章不少,官方文檔介紹的也比較詳細,本篇文章不介紹HBase基本的細節。apache
本文從 HBase 寫鏈路開始分析,而後針對少許隨機讀和海量隨機寫入場景入手,全方面量化分析各類資源的開銷, 從而作到如下兩點:服務器
HBase 的寫入鏈路基於 LSM(Log-Structured Merge-Tree), 基本思想是把用戶的隨機寫入轉化爲兩部分寫入:網絡
Memstore 內存中的 Map, 保存隨機的隨機寫入,待 memstore 達到必定量的時候會異步執行 flush 操做,在 HDFS 中生成 HFile 中。 同時會按照寫入順序,把數據寫入一份到 HDFS 的 WAL(Write Ahead Log)中,用來保證數據的可靠性,即在異常(宕機,進程異常退出)的場景下,可以恢復 Memstore 中還沒來得及持久化成 HFile 的數據.異步
上一節中,介紹了 HBase 的寫路徑,其中 HFile 是 HBase 數據持久化的最終形態, 本節將介紹 HBase 如何生成 HFile 和管理 HFile。關於 HFile, 主要涉及到兩個核心操做:分佈式
上一節中提到,HBase 的寫入最早會放入內存中,提供實時的查詢,當 Memstore 中數據達到必定量的閾值(128MB),會經過 Flush 操做生成 HFile 持久化到 HDFS 中,隨着用戶的寫入,生成的 HFile 數目會逐步增多,這會影響用戶的讀操做,同時也會系統佔用(HDFS 層 block 的數目, regionserver 服務器的文件描述符佔用), region split 操做,region reopen 操做也會受到不一樣程度影響。
HBase 經過 Compaction 機制將多個 HFile 合併成一個 HFile 以控制每一個 Region 內的 HFile 的數目在必定範圍內, 固然 Compaction 還有其餘的做用,好比數據本地化率,多版本數據的合併,數據刪除標記的清理等等,本文不作展開。性能
另外還有一點須要知道的是,HBase 中 Flush 操做和 Compaction 操做和讀寫鏈路是由獨立線程完成的,互不干擾。大數據
爲了簡化計算,本節針對事件類數據寫吞吐型場景,對 HBase 系統中的開銷作定量的分析,作如下假設:優化
以上 11 個參數,是本次量化分析中須要使用到的變量,系統資源方面主要量化如下兩個指標:網站
這裏只考慮磁盤空間方面的佔用,相關的變量有:ui
HFile的磁盤容量量化公式
V = TTL 86400 T s C * R1
假設 s = 1000, TTL = 365, T = 200000, C = 0.2 , R1 = 3 的狀況下,HFile 磁盤空間需求是:
V = 30 * 86400 * 200000 * 1000 * 0.2 * 3 = 311040000000000.0 bytes = 282T
在這裏咱們忽略了其餘佔用比較小的磁盤開銷,好比:
HBase中會形成巨大網絡開銷的主要由一下三部分組成,他們是相互獨立,異步進行的,這裏作個比方,HBase 這三個操做和人吃飯很像,這裏作個類比
迴歸正題,下面按照發生順序,從三個角度分別分析:
寫路徑的網絡開銷,主要是寫 WAL 日誌方面, 相關的變量有:
寫路徑中,產生的網絡流量分爲兩部分,一部分是寫 WAL 產生的流量,一部分是外部用戶 RPC 寫入的流量, In 流量和 Out 流量計算公式爲:
NInWrite = T s Cwal (R2 - 1) + (T s )NOutWrite = T s Cwal * (R2 - 1)
假設 T = 20W,s = 1000, Cwal = 1.0, R2 = 3
NInwrite = 200000 * 1000 * 1 * (3-1) + 200000 * 1000 = 600000000 bytes/s = 572MB/s NOutwrite = 200000 * 1000* 1 * (3-1) = 400000000 bytes/s = 381MB/s
Flush 的網絡開銷,主要是生成 HFile 後,將 HFile 寫入到 HDFS 的過程,相關的變量有:
Flush 產生的 In 流量和 Out 流量計算公式爲:
NInWrite = s T (R1 - 1) * CNOutWrite = s T (R1 - 1) * C
假設 T = 20W, S = 1000, R1 = 3, C = 0.2
NInwrite = 200000 * 1000 * (3 - 1) * 0.2 = 80000000.0 bytes/s =76.3MB/s NOutwrite = 200000 * 1000 * (3 - 1) * 0.2 = 120000000.0 bytes/s =76.3MB/s
Compaction 比較複雜,在有預分區不考慮 Split 的狀況下分爲兩類:
二者是獨立的,下面將分別針對兩種 Compaction 作分析,最後取和:
Major Compaction 的定義是由所有 HFile 參與的 Compaction, 通常在發生在 Split 後發生,或者到達系統的 MajorCompaction 週期, 默認的 MajorCompaction 週期爲 20 天,這裏咱們暫時忽略 Split 形成的 MajorCompaction 流量. 最終 Major Compaction 開銷相關的變量是:
這裏假設數據是有本地化的,因此 MajorCompaction 的讀過程,走 ShortCircuit,不計算網絡開銷,而且寫 HFile 的第一副本是本地流量,也不作流量計算,因此 MajorCompaction 的網絡流量計算公式是:
NInMajor = D * (R1 - 1) / MNOutMajor = D * (R1 - 1) / M
假設 D = 10T, R1 = 3, M = 20
NInMajor = 10 * 1024 * 1024 * 1024 * 1024 * (3 - 1) / (20 * 86400) = 12725829bytes/s = 12MB/s NOutMajor = 10 * 1024 * 1024 * 1024 * 1024 * (3 - 1) / (20 * 86400) = 12725829bytes /s = 12MB/s
量化以前,先問一個問題,每條數據在第一次 flush 成爲 HFile 以後,會通過多少次 Minor Compaction?
要回答這個問題以前,要先了解如今 HBase 默認的 compaction 的文件選取策略,這裏不展開,只作簡單分析,MinorCompaction 選擇的文件對象數目,通常處於 hbase.hstore.compaction.min(默認 3)和 hbase.hstore.compaction.max(默認 10)之間, 總文件大小小於 hbase.hstore.compaction.max.size(默認 Max), 若是文件的 Size 小於 hbase.hstore.compaction.min.size(默認是 flushsize), 則必定會被選中; 而且被選中的文件size的差距不會過大, 這個由參數 hbase.hstore.compaction.ratio 和 hbase.hstore.compaction.ratio.offpeak 控制,這裏不作展開.
因此,在 Compaction 沒有積壓的狀況下,每次 compaction 選中的文件數目會等於 hbase.hstore.compaction.min 而且文件 size 應該相同量級, 對穩定的表,對每條數據來講,通過的 compaction 次數越多,其文件會越大. 其中每條數據參與 Minor Compaction 的最大次數能夠用公式 math.log( 32000 / 25.6, 3) = 6 獲得
這裏用到的兩個變量是:
因此剛剛 Flush 生成的 HFile 的大小在 25.6MB 左右,當集齊三個 25.6MB 的 HFile 後,會觸發第一次 Minor Compaction, 生成一個 76.8MB 左右的 HFile
對於通常狀況,單個 Region 的文件 Size 咱們會根據容量預分區好,而且控制單個 Region 的 HFile 的總大小 在 32G 之內,對於一個 Memstore
128MB, HFile 壓縮比 0.2, 單個 Region 32G 的表,上表中各個 Size 的 HFile 數目不會超過 2 個(不然就知足了觸發 Minor Compaction 的條件)
32G = 18.6G + 6.2G + 6.2G + 690MB + 230MB + 76.8MB + 76.8MB
到這裏,咱們知道每條寫入的數據,從寫入到 TTL 過時,通過 Minor Compaction 的次數是能夠計算出來的。 因此只要計算出每次 Compaction 的網絡開銷,就能夠計算出,HBase 經過 Minor Compaction 消化每條數據,所佔用的總的開銷是多少,這裏用到的變量有:
計算公式以下:
NInMinor = S T (R1-1) C 總次數NOutMinor = S T (R1-1) C 總次數
假設 S = 1000, T = 20W, R1 = 3, C = 0.2, 總次數 = 6
NInminor = 1000 * 200000 * (3 - 1) * 0.2 * 6 = 480000000.0bytes/s = 457.8MB/s NOutminor = 1000 * 200000 * (3 - 1) * 0.2 * 6 = 480000000.0bytes/s = 457.8MB/s
在用戶寫入 TPS 20W, 單條數據大小 1000 bytes的場景下,總體網絡吞吐爲:
NIntotal = NInwrite + NInflush + NInmajor + NInminor = 572MB/s + 76.3MB/s + 12MB/s + 457.8MB/s = 1118.1MB/s NOuttotal = NOutwrite + NOutflush + NOutmajor + NOutminor = 381MB/s + 76.3MB/s + 12MB/s + 457.8MB/s = 927.1MB
固然這是理想狀況下的最小開銷,有不少種狀況,能夠致使實際網絡開銷超過這個理論值, 如下狀況都會致使實際流量的升高:
有了這個量化分析後,咱們能作什麼優化呢? 這裏不深刻展開,簡單說幾點已經在有贊生產環境獲得驗證具備實效的優化點:
到這裏,HBase 的寫吞吐場景的資源定量分析和優化的介紹就算結束了,本文基於 HBase1.2.6 版本。 對不少 HBase 的細節沒有作展開說明,有些地方由於做者認知有限,不免紕漏,歡迎各位同行指出。
最後打個小廣告,有贊大數據團隊基礎設施團隊,主要負責有讚的數據平臺(DP), 實時計算(Storm, Spark Streaming, Flink),離線計算(HDFS,YARN,HIVE, SPARK SQL),在線存儲(HBase),實時 OLAP(Druid) 等數個技術產品,歡迎感興趣的小夥伴聯繫 hefei@youzan.com
參考文獻