HBase寫吞吐場景資源消耗量化分析及優化

一. 概述

HBase 是一個基於 Google BigTable 論文設計的高可靠性、高性能、可伸縮的分佈式存儲系統。 網上關於 HBase 的文章不少,官方文檔介紹的也比較詳細,本篇文章不介紹HBase基本的細節。apache

本文從 HBase 寫鏈路開始分析,而後針對少許隨機讀和海量隨機寫入場景入手,全方面量化分析各類資源的開銷, 從而作到如下兩點:服務器

  1. 在給定業務量級的狀況下,預先評估好集羣的合理規模
  2. 在 HBase 的衆多參數中,選擇合理的配置組合

二. HBase 寫鏈路簡要分析

HBase 的寫入鏈路基於 LSM(Log-Structured Merge-Tree), 基本思想是把用戶的隨機寫入轉化爲兩部分寫入:網絡

Memstore 內存中的 Map, 保存隨機的隨機寫入,待 memstore 達到必定量的時候會異步執行 flush 操做,在 HDFS 中生成 HFile 中。 同時會按照寫入順序,把數據寫入一份到 HDFS 的 WAL(Write Ahead Log)中,用來保證數據的可靠性,即在異常(宕機,進程異常退出)的場景下,可以恢復 Memstore 中還沒來得及持久化成 HFile 的數據.異步

圖片描述

三. Flush & Compaction

上一節中,介紹了 HBase 的寫路徑,其中 HFile 是 HBase 數據持久化的最終形態, 本節將介紹 HBase 如何生成 HFile 和管理 HFile。關於 HFile, 主要涉及到兩個核心操做:分佈式

  1. Flushing
  2. Compaction

上一節中提到,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 系統中的開銷作定量的分析,作如下假設:優化

  1. 數據寫入的 Rowkey 是打散的,不存在寫熱點
  2. 數據寫入量及總量是可評估的,會對數據作預先分區,定量分析基於 region 分佈穩定的狀況下
  3. 假設隨機讀的數目很小,小到能夠忽略 IO 開銷,且對讀 RT 不敏感
  4. 數據沒有更新,沒有刪除操做,有生命週期TTL設置
  5. HBase 寫入鏈路中不存在隨機磁盤,因此隨機 IOPS 不會成爲瓶頸
  6. 通常大數據機型的多個 SATA 盤的順序寫吞吐大於萬兆網卡
  7. 忽略掉RPC帶來的額外的帶寬消耗

4.1 系統變量

  1. 單條數據大小 -> s (bytes)
  2. 峯值寫 TPS -> T
  3. HFile 副本數→ R1 (通常爲3)
  4. WAL 副本數 → R2 (通常爲3)
  5. WAL 數據壓縮比 → Cwal (通常是1)
  6. HFile 壓縮比 → C (採用 DIFF + LZO, 日誌場景壓縮比通常爲 0.2左右)
  7. FlushSize → F (這裏跟 regionserver 的 memstore 內存容量,region 數目,寫入是否平均和 flushsize 的配置有關,簡化分析,認爲內存是足夠的 128MB)
  8. hbase.hstore.compaction.min → CT (默認是 3, 通常狀況下,決定了歸併係數,即每次 compaction 參與的文件數目,在不存在 compaction 積壓的狀況下, 實際運行時也是在 3 左右)
  9. 數據生命週期 → TTL (決定數據量的大小,通常寫吞吐場景,日誌會有必定的保存週期, 單位天)
  10. 單機數據量水位 → D ( 單位 T,這裏指 HDFS 上存放 HFile 數據的數據量平均分擔到每臺機器上)
  11. MajorCompaction 週期 → M( hbase.hregion.majorcompaction 決定,默認 20 天)

以上 11 個參數,是本次量化分析中須要使用到的變量,系統資源方面主要量化如下兩個指標:網站

  1. 磁盤開銷
  2. 網絡開銷

4.2 磁盤容量開銷量化分析

這裏只考慮磁盤空間方面的佔用,相關的變量有:ui

  1. 單條數據大小 s
  2. 峯值寫入 TPS
  3. HFile 副本數 R1
  4. HFile 壓縮比 c
  5. 數據生命週期 TTL

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

在這裏咱們忽略了其餘佔用比較小的磁盤開銷,好比:

  1. WAL的磁盤開銷,在沒有 Replication,寫入平均的狀況下,WAL 的日誌量約定於 (hbase.master.logcleaner.ttl /1000) s TPS + totalMemstoreSize
  2. Compaction 臨時文件,Split 父 Region 文件等臨時文件
  3. Snapshot 文件
  4. 等等

4.3 網絡開銷量化分析

HBase中會形成巨大網絡開銷的主要由一下三部分組成,他們是相互獨立,異步進行的,這裏作個比方,HBase 這三個操做和人吃飯很像,這裏作個類比

圖片描述

迴歸正題,下面按照發生順序,從三個角度分別分析:

  1. 寫路徑
  2. Flush
  3. Compaction

4.3.1 寫路徑

寫路徑的網絡開銷,主要是寫 WAL 日誌方面, 相關的變量有:

  1. 單條數據大小 s
  2. 峯值寫入 TPS
  3. WAL 副本數 R2
  4. WAL 壓縮比 Cwal

寫路徑中,產生的網絡流量分爲兩部分,一部分是寫 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

4.3.2 Flush

Flush 的網絡開銷,主要是生成 HFile 後,將 HFile 寫入到 HDFS 的過程,相關的變量有:

  1. 單條數據大小 s
  2. 峯值寫入 T
  3. HFIle 副本數 R1
  4. HFile 壓縮比 C

Flush 產生的 In 流量和 Out 流量計算公式爲:

NInWrite = s T (R1 - 1) * C

NOutWrite = 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

4.3.3 Compaction

Compaction 比較複雜,在有預分區不考慮 Split 的狀況下分爲兩類:

  1. Major Compaction
  2. Minor Compaction

二者是獨立的,下面將分別針對兩種 Compaction 作分析,最後取和:

4.3.3.1 Major Compaction

Major Compaction 的定義是由所有 HFile 參與的 Compaction, 通常在發生在 Split 後發生,或者到達系統的 MajorCompaction 週期, 默認的 MajorCompaction 週期爲 20 天,這裏咱們暫時忽略 Split 形成的 MajorCompaction 流量. 最終 Major Compaction 開銷相關的變量是:

  1. 單機數據量水位 D
  2. HFIle 副本數 R1
  3. MajorCompaction 週期 → M (默認 20 天)

這裏假設數據是有本地化的,因此 MajorCompaction 的讀過程,走 ShortCircuit,不計算網絡開銷,而且寫 HFile 的第一副本是本地流量,也不作流量計算,因此 MajorCompaction 的網絡流量計算公式是:

NInMajor = D * (R1 - 1) / M

NOutMajor = 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

4.3.3.2 Minor Compaction

量化以前,先問一個問題,每條數據在第一次 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 獲得

這裏用到的兩個變量是:

  1. FlushSize 默認是 128 MB
  2. HFile 壓縮比例,假設是 0.2

因此剛剛 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 消化每條數據,所佔用的總的開銷是多少,這裏用到的變量有:

  1. 單條數據大小 s
  2. 峯值寫入 T
  3. HFIle 副本數 R1
  4. HFile 壓縮比 C

計算公式以下:

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

4.3.4 網絡資源定量分析小結

在用戶寫入 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

固然這是理想狀況下的最小開銷,有不少種狀況,能夠致使實際網絡開銷超過這個理論值, 如下狀況都會致使實際流量的升高:

  1. 預分區不足或者業務量增加,致使 Region 發生 Split, Split 會致使額外的 Compaction 操做
  2. 分區寫入不平均,致使少許 region 不是由於到達了 flushsize 而進行 flush,致使 flush 下來的文件 Size 偏小
  3. HFile 由於 balance 等緣由致使本地化率低,也會致使 compaciton 產生更多的網卡開銷
  4. 預分區數目過多,致使全局 memstore 水位高,memstore 沒辦法到達 flushsize 進行 flush,從而全局都 flush 出比較小的文件
  5. 等等

有了這個量化分析後,咱們能作什麼優化呢? 這裏不深刻展開,簡單說幾點已經在有贊生產環境獲得驗證具備實效的優化點:

  1. 業務接入初期,協助業務作 Rowkey 的設計,避免寫入熱點
  2. 增長 hbase.hstore.compaction.min,增長每次 Compaction參加的文件數,至關於減小了每條數據整個生命週期經歷過的 Compaction 次數
  3. 根據業務穩態的規模,作好預分區,儘可能減小 Split 形成的額外開銷
  4. 對於讀 RT 不敏感的業務,能夠設置 hbase.hstore.compaction.max.size 爲 4g,儘量減小過大的文件作 Compaction,由於大文件作 compaction 的 ROI 實在過低
  5. 對於沒有多版本而且有 TTL 的數據,能夠關閉系統的 MajorCompaction 週期,數據過時採用文件總體過時的方式,消除 MajorCompaction 的系統開銷
  6. 對於吞吐大的場景,用戶在寫入數據的時候就對數據作壓縮,減少寫路徑形成的網絡開銷,畢竟 WAL 是不能壓縮的(壓縮功能形同虛設)
  7. 調整 Memstore 的內存比例,保證單機上每一個 Region 儘量的分配到 Flushsize 大小的內存,儘量的 flush 大文件,從而減小後續 Compaction 開銷

五. 總結

到這裏,HBase 的寫吞吐場景的資源定量分析和優化的介紹就算結束了,本文基於 HBase1.2.6 版本。 對不少 HBase 的細節沒有作展開說明,有些地方由於做者認知有限,不免紕漏,歡迎各位同行指出。

最後打個小廣告,有贊大數據團隊基礎設施團隊,主要負責有讚的數據平臺(DP), 實時計算(Storm, Spark Streaming, Flink),離線計算(HDFS,YARN,HIVE, SPARK SQL),在線存儲(HBase),實時 OLAP(Druid) 等數個技術產品,歡迎感興趣的小夥伴聯繫 hefei@youzan.com

參考文獻

  1. Google BigTable
  2. HBase 官方網站

圖片描述

相關文章
相關標籤/搜索