Hbase性能優化百科全書

file

本文集合了小編在平常學習和生產實踐中遇到的使用Hbase中的各類問題和優化方法,分別從表設計、rowkey設計、內存、讀寫、配置等各個領域對Hbase經常使用的調優方式進行了總結,但願能對讀者有幫助。本文參考結合本身實際優化經驗,參考了大量官網和各個前輩的經驗,生產環境中的Hbase集羣支撐了約50萬/s的讀和25萬/s的寫流量洪峯。感謝各位的經驗和付出。html

HBase簡介

HBase是一個分佈式的、面向列的開源數據庫存儲系統,是對Google論文BigTable的實現,具備高可靠性、高性能和可伸縮性,它能夠處理分佈在數千臺通用服務器上的PB級的海量數據。BigTable的底層是經過GFS(Google文件系統)來存儲數據,而HBase對應的則是經過HDFS(Hadoop分佈式文件系統)來存儲數據的。算法

HBase不一樣於通常的關係型數據庫,它是一個適合於非結構化數據存儲的數據庫。HBase不限制存儲的數據的種類,容許動態的、靈活的數據模型。HBase能夠在一個服務器集羣上運行,而且可以根據業務進行橫向擴展。shell

Hbase有如下優勢:數據庫

  • 海量存儲:HBase適合存儲PB級別的海量數據,在PB級別的數據以及採用廉價PC存儲的狀況下,能在幾十到百毫秒內返回數據。這與HBase的記憶擴展性息息相關。正是由於HBase的良好擴展性,才爲海量數據的存儲提供了便利。
  • 列式存儲:列式存儲,HBase是根據列族來存儲數據的。列族下面能夠有很是多的列,列族在建立表的時候就必須指定,而不用指定列。
  • 極易擴展:HBase的擴展性主要體如今兩個方面,一個是基於上層處理能力(RegionServer)的擴展,一個是基於存儲能力(HDFS)的擴展。
  • 高併發:目前大部分使用HBase的架構,都是採用廉價PC,所以單個IO的延遲其實並不小,通常在幾十到上百ms之間。這裏說的高併發,主要是在併發的狀況下,HBase的單個IO延遲降低並很少。
  • 稀疏:稀疏主要是針對HBase列的靈活性,在列族中,能夠指定任意多的列,在列數據爲空的狀況下,是不會佔用存儲空間。

file

從咱們使用Hbase開始,開發和調優將會一直伴隨在系統的整個生命週期。筆者將對本身熟悉和使用過的調優方式進行一一概括和總結。apache

表的設計之預分區

HBase表在剛剛被建立時,只有1個分區(region),當一個region過大(達到hbase.hregion.max.filesize屬性中定義的閾值,默認10GB)時表將會進行split,分裂爲2個分區。表在進行split的時候,會耗費大量的資源,頻繁的分區對HBase的性能有巨大的影響。HBase提供了預分區功能,即用戶能夠在建立表的時候對錶按照必定的規則分區。數組

若是業務要進行預分區,首先要明確rowkey的取值範圍或構成邏輯,假設咱們的rowkey組成爲例:兩位隨機數+時間戳+客戶號,兩位隨機數的範圍從00-99,因而我劃分了10個region來存儲數據,每一個region對應的rowkey範圍以下:-10,10-20,20-30,30-40,40-50,50-60,60-70,70-80,80-90,90-。緩存

表的設計之rowkey

咱們在以前的文章《HBase優化筆記》《設計HBase RowKey須要注意的二三事》中詳細講解過。性能優化

在HBase中,定位一條數據(即一個Cell)須要4個維度的限定:行鍵(RowKey)、列族(Column Family)、列限定符(Column Qualifier)、時間戳(Timestamp)。其中,RowKey是最容易出現問題的。除了根據業務和查詢需求來設計以外,還須要注意如下三點。服務器

打散RowKey

HBase中的行是按照RowKey字典序排序的。
這對Scan操做很是友好,由於RowKey相近的行老是存儲在相近的位置,順序讀的效率比隨機讀要高。
可是,若是大量的讀寫操做老是集中在某個RowKey範圍,那麼就會形成Region熱點,拖累RegionServer的性能。
所以,要適當地將RowKey打散。網絡

加鹽(salting)+哈希(hashing)

這裏的「加鹽」與密碼學中的「加鹽」不是一回事。
它是指在RowKey的前面增長一些前綴。
加鹽的前綴種類越多,RowKey就被打得越散。
前綴不能夠是隨機的,由於必需要讓客戶端可以完整地重構RowKey。
咱們通常會拿原RowKey或其一部分計算hash值,而後再對hash值作運算做爲前綴。

反轉固定格式的數值

以手機號爲例,手機號的前綴變化比較少(如15二、185等),但後半部分變化不少。
若是將它反轉過來,能夠有效地避免熱點。
不過其缺點就是失去了有序性。
反轉時間
這個操做嚴格來說不算「打散」,但能夠調整數據的時間排序。
若是將時間按照字典序排列,最近產生的數據會排在舊數據後面。
若是用一個大值減去時間(好比用99999999減去yyyyMMdd,或者Long.MAX_VALUE減去時間戳),最新的數據就能夠排在前面了。

控制RowKey長度

在HBase中,RowKey、列族、列名等都是以byte[]形式傳輸的。
RowKey的最大長度限制爲64KB,但在實際應用中最多不會超過100B。
設計短RowKey有如下兩方面考慮:

在HBase的底層存儲HFile中,RowKey是KeyValue結構中的一個域。假設RowKey長度100B,那麼1000萬條數據中,只算RowKey就佔用掉將近1G空間,會影響HFile的存儲效率。
file

HBase中設計有MemStore和BlockCache,分別對應列族/Store級別的寫入緩存,和RegionServer級別的讀取緩存。若是RowKey過長,緩存中存儲數據的密度就會下降,影響數據落地或查詢效率。
file

另外,咱們目前使用的服務器操做系統都是64位系統,內存是按照8B對齊的,所以設計RowKey時通常作成8B的整數倍,如16B或者24B,能夠提升尋址效率。
一樣地,列族、列名的命名在保證可讀的狀況下也應儘可能短。HBase官方不推薦使用3個以上列族,所以實際上列族命名幾乎都用一個字母,好比‘c’或‘f’。

保證RowKey惟一性

這個就是顯而易見的了,再也不贅述。

JVM調優

這部分咱們能夠參考禪克大佬發表的一些關於Hbase 內存設置的東西。

合理配置 JVM 內存

首先涉及 HBase 服務的堆內存設置。通常剛部署的 HBase 集羣,默認配置只給 Master 和 RegionServer 分配了 1G 的內存,RegionServer 中 MemStore 默認佔 0.4 即 400MB 左右的空間,而一個 MemStore 刷寫閾值默認 128M,因此一個 RegionServer 也就能正常管理 3 個Region,多了就可能會產生小文件了,另外也容易發生 Full GC。所以建議合理調整 Master 和 RegionServer 的內存,好比:

export HBASE_MASTER_OPTS="$HBASE_MASTER_OPTS -Xms8g -Xmx8g"
export HBASE_REGIONSERVER_OPTS="$HBASE_REGIONSERVER_OPTS -Xms32g -Xmx32g"

這裏也要根據實際集羣資源進行配置,另外要牢記至少留 10% 的內存給操做系統使用。

選擇合適的GC策略

另外一個重要方面是 HBase JVM 的 GC 優化,其實 HBase 讀寫路徑上的不少設計都是圍繞 GC 優化作的。選擇合適的 GC 策略很是重要,對於 HBase 而言一般有兩種可選 GC 方案:

  • ParallelGC 和 CMS 組合
  • G1

CMS 避免不了 Full GC,並且 Full GC 場景下會經過一次串行的完整垃圾收集來回收碎片化的內存,這個過程一般會比較長,應用線程會發生長時間的 STW 停頓,不響應任何請求;而 G1 適合大內存的場景,經過把堆內存劃分爲多個 Region(不是 HBase 中的 Region),而後對各個 Region 單獨進行 GC,這樣就具備了並行整理內存碎片的功能,能夠最大限度的避免 Full GC 的到來,提供更加合理的停頓時間。

因爲 Master 只是作一些管理操做,實際處理讀寫請求和存儲數據的都是 RegionServer 節點,因此通常內存問題都出在 RegionServer 上。

這裏給的建議是,小堆(4G及如下)選擇 CMS,大堆(32G及以上)考慮用 G1,若是堆內存介入 4~32G 之間,可自行測試下兩種方案。剩下來的就是 GC 參數調優了。

開啓 MSLAB 功能

這是 HBase 本身實現了一套以 MemStore 爲最小單元的內存管理機制,稱爲 MSLAB(MemStore-Local Allocation Buffer),主要做用是爲了減小內存碎片化,改善 Full GC 發生的狀況。

MemStore 會在內部維護一個 2M 大小的 Chunk 數組,當寫入數據時會先申請 2M 的 Chunk,將實際數據寫入該 Chunk中,當該 Chunk 滿了之後會再申請一個新的 Chunk。這樣 MemStore Flush 後會達到粗粒度化的內存碎片效果,能夠有效下降 Full GC 的觸發頻率。

HBase 默認是開啓 MSLAB 功能的,和 MSLAB 相關的配置包括:

  • hbase.hregion.memstore.mslab.enabled:MSLAB 開關,默認爲 true,即打開 MSLAB。
  • hbase.hregion.memstore.mslab.chunksize:每一個 Chunk 的大 小,默認爲 2MB,建議保持默認值。
  • hbase.hregion.memstore.chunkpool.maxsize:內部 Chunk Pool 功能,默認爲 0 ,即關閉 Chunk Pool 功能。設置爲大於 0 的值才能開啓,取值範圍爲 [0,1],表示 Chunk Pool 佔整個 MemStore 內存大小的比例。
  • hbase.hregion.memstore.chunkpool.initialsize:表示初始化時申請多少個 Chunk 放到 Chunk Pool 中,默認爲 0,即初始化時不申請 Chuck,只在寫入數據時才申請。
  • hbase.hregion.memstore.mslab.max.allocation:表示能放入 MSLAB 的最大單元格大小,默認爲 256KB,超過該大小的數據將從 JVM 堆分配空間而不是 MSLAB。

出於性能優化考慮,建議檢查相關配置,確保 MSLAB 處於開啓狀態。

考慮開啓 BucketCache

這塊涉及到讀緩存 BlockCache 的策略選擇。首先,BlockCache 是 RegionServer 級別的,一個 RegionServer 只有一個 BlockCache。BlockCache 的工做原理是讀請求會首先檢查 Block 是否存在於 BlockCache,存在就直接返回,若是不存在再去 HFile 和 MemStore 中獲取,返回數據時把 Block 緩存到 BlockCache 中,後續同一請求或臨近查詢能夠直接從 BlockCache 中獲取,避免過多的昂貴 IO 操做。BlockCache 默認是開啓的。

目前 BlockCache 的實現方案有三種:

(1) LRUBlockCache
最先的 BlockCache 方案,也是 HBase 目前默認的方案。LRU 是 Least Recently Used 的縮寫,稱爲近期最少使用算法。LRUBlockCache 參考了 JVM 分代設計的思想,採用了緩存分層設計。

LRUBlockCache 將整個 BlockCache 分爲 single-access(單次讀取區)、multi-access(屢次讀取區)和 in-memory 三部分,默認分別佔讀緩存的25%、50%、25%。其中設置 IN_MEMORY=true 的列族,Block 被讀取後纔會直接放到 in-memory 區,所以建議只給那些數據量少且訪問頻繁的列族設置 IN_MEMORY 屬性。另外,HBase 元數據好比 meta 表、namespace 表也都緩存在 in-memory 區。

(2) SlabCache
HBase 0.92 版本引入的一種方案,起初是爲了不 Full GC 而引入的一種堆外內存方案,並與 LRUBlockCache 搭配使用,後來發現它對 Full GC 的改善很小,以致於這個方案基本被棄用了。

(3) BucketCache
HBase 0.96 版本引入的一種方案,它借鑑了 SlabCache 的設計思想,是一種很是高效的緩存方案。實際應用中,HBase 將 BucketCache 和 LRUBlockCache 搭配使用,稱爲組合模式(CombinedBlockCahce),具體地說就是把不一樣類型的 Block 分別放到 LRUBlockCache 和 BucketCache 中。

HBase 會把 Index Block 和 Bloom Block 放到 LRUBlockCache 中,將 Data Block 放到 BucketCache 中,因此讀取數據會去 LRUBlockCache 查詢一下 Index Block,而後再去 BucketCache 中查詢真正的數據。

BucketCache 涉及的經常使用參數有:

  • hbase.bucketcache.ioengine:使用的存儲介質,可設置爲 heap、offheap 或 file,其中 heap 表示空間從JVM堆中申請,offheap 表示使用 DirectByteBuffer 技術實現堆外內存管理,file 表示使用相似 SSD 等存儲介質緩存數據。默認值爲空,即關閉 BucketCache,通常建議開啓 BucketCache。此外,HBase 2.x 再也不支持 heap 選型。
  • hbase.bucketcache.combinedcache.enabled:是否打開 CombinedBlockCache 組合模式,默認爲 true。此外,HBase 2.x 再也不支持該參數。
  • hbase.bucketcache.size:BucketCache 大小,取值有兩種,一種是[0,1]之間的浮點數值,表示佔總內存的百分比,另外一種是大於1的值,表示佔用內存大小,單位 MB。

根據上面的分析,通常建議開啓 BucketCache,綜合考慮成本和性能,建議比較合理的介質是:LRUBlockCache 使用內存,BuckectCache 使用SSD,HFile 使用機械磁盤。

合理配置讀寫緩存比例

HBase 爲了優化性能,在讀寫路徑上分別設置了讀緩存和寫緩存,參數分別是 hfile.block.cache.size 與 hbase.regionserver.global.memstore.size,默認值都是 0.4,表示讀寫緩存各佔 RegionServer 堆內存的 40%。

在一些場景下,咱們能夠適當調整兩部分比例,好比寫多讀少的場景下咱們能夠適當調大寫緩存,讓 HBase 更好的支持寫業務,相反相似,總之兩個參數要配合調整。

讀優化

咱們在以前《HBase生產環境優化不徹底指南》一文中也提到過,你們能夠參考這裏。範欣欣前輩曾經就讀寫問題提過很是好的建議(http://hbasefly.com/),很是建議你們仔細讀一讀。

file

HBase客戶端優化

和大多數系統同樣,客戶端做爲業務讀寫的入口,姿式使用不正確一般會致使本業務讀延遲較高實際上存在一些使用姿式的推薦用法,這裏通常須要關注四個問題:

1. scan緩存是否設置合理?

優化原理:在解釋這個問題以前,首先須要解釋什麼是scan緩存,一般來說一次scan會返回大量數據,所以客戶端發起一次scan請求,實際並不會一次就將全部數據加載到本地,而是分紅屢次RPC請求進行加載,這樣設計一方面是由於大量數據請求可能會致使網絡帶寬嚴重消耗進而影響其餘業務,另外一方面也有可能由於數據量太大致使本地客戶端發生OOM。在這樣的設計體系下用戶會首先加載一部分數據到本地,而後遍歷處理,再加載下一部分數據到本地處理,如此往復,直至全部數據都加載完成。數據加載到本地就存放在scan緩存中,默認100條數據大小。

一般狀況下,默認的scan緩存設置就能夠正常工做的。可是在一些大scan(一次scan可能須要查詢幾萬甚至幾十萬行數據)來講,每次請求100條數據意味着一次scan須要幾百甚至幾千次RPC請求,這種交互的代價無疑是很大的。所以能夠考慮將scan緩存設置增大,好比設爲500或者1000就可能更加合適。筆者以前作過一次試驗,在一次scan掃描10w+條數據量的條件下,將scan緩存從100增長到1000,能夠有效下降scan請求的整體延遲,延遲基本下降了25%左右。

優化建議:大scan場景下將scan緩存從100增大到500或者1000,用以減小RPC次數

2. get請求是否可使用批量請求?

優化原理:HBase分別提供了單條get以及批量get的API接口,使用批量get接口能夠減小客戶端到RegionServer之間的RPC鏈接數,提升讀取性能。另外須要注意的是,批量get請求要麼成功返回全部請求數據,要麼拋出異常。

優化建議:使用批量get進行讀取請求

3. 請求是否能夠顯示指定列族或者列?

優化原理:HBase是典型的列族數據庫,意味着同一列族的數據存儲在一塊兒,不一樣列族的數據分開存儲在不一樣的目錄下。若是一個表有多個列族,只是根據Rowkey而不指定列族進行檢索的話不一樣列族的數據須要獨立進行檢索,性能必然會比指定列族的查詢差不少,不少狀況下甚至會有2倍~3倍的性能損失。

優化建議:能夠指定列族或者列進行精確查找的儘可能指定查找

4. 離線批量讀取請求是否設置禁止緩存?

優化原理:一般離線批量讀取數據會進行一次性全表掃描,一方面數據量很大,另外一方面請求只會執行一次。這種場景下若是使用scan默認設置,就會將數據從HDFS加載出來以後放到緩存。可想而知,大量數據進入緩存必將其餘實時業務熱點數據擠出,其餘業務不得不從HDFS加載,進而會形成明顯的讀延遲毛刺

優化建議:離線批量讀取請求設置禁用緩存,scan.setBlockCache(false)

HBase服務器端優化

通常服務端端問題一旦致使業務讀請求延遲較大的話,一般是集羣級別的,即整個集羣的業務都會反映讀延遲較大。能夠從4個方面入手:

5. 讀請求是否均衡?

優化原理:極端狀況下假如全部的讀請求都落在一臺RegionServer的某幾個Region上,這一方面不能發揮整個集羣的併發處理能力,另外一方面勢必形成此臺RegionServer資源嚴重消耗(好比IO耗盡、handler耗盡等),落在該臺RegionServer上的其餘業務會所以受到很大的波及。可見,讀請求不均衡不只會形成自己業務性能不好,還會嚴重影響其餘業務。固然,寫請求不均衡也會形成相似的問題,可見負載不均衡是HBase的大忌。

觀察確認:觀察全部RegionServer的讀請求QPS曲線,確認是否存在讀請求不均衡現象

優化建議:RowKey必須進行散列化處理(好比MD5散列),同時建表必須進行預分區處理

6. BlockCache是否設置合理?

優化原理:BlockCache做爲讀緩存,對於讀性能來講相當重要。默認狀況下BlockCache和Memstore的配置相對比較均衡(各佔40%),能夠根據集羣業務進行修正,好比讀多寫少業務能夠將BlockCache佔比調大。另外一方面,BlockCache的策略選擇也很重要,不一樣策略對讀性能來講影響並非很大,可是對GC的影響卻至關顯著,尤爲BucketCache的offheap模式下GC表現很優越。另外,HBase 2.0對offheap的改造(HBASE-11425)將會使HBase的讀性能獲得2~4倍的提高,同時GC表現會更好!

觀察確認:觀察全部RegionServer的緩存未命中率、配置文件相關配置項一級GC日誌,確認BlockCache是否能夠優化

優化建議:JVM內存配置量 < 20G,BlockCache策略選擇LRUBlockCache;不然選擇BucketCache策略的offheap模式;期待HBase 2.0的到來!

7. HFile文件是否太多?

優化原理:HBase讀取數據一般首先會到Memstore和BlockCache中檢索(讀取最近寫入數據&熱點數據),若是查找不到就會到文件中檢索。HBase的類LSM結構會致使每一個store包含多數HFile文件,文件越多,檢索所需的IO次數必然越多,讀取延遲也就越高。文件數量一般取決於Compaction的執行策略,通常和兩個配置參數有關:hbase.hstore.compactionThreshold和hbase.hstore.compaction.max.size,前者表示一個store中的文件數超過多少就應該進行合併,後者表示參數合併的文件大小最大是多少,超過此大小的文件不能參與合併。這兩個參數不能設置太’鬆’(前者不能設置太大,後者不能設置過小),致使Compaction合併文件的實際效果不明顯,進而不少文件得不到合併。這樣就會致使HFile文件數變多。

觀察確認:觀察RegionServer級別以及Region級別的storefile數,確認HFile文件是否過多

優化建議:hbase.hstore.compactionThreshold設置不能太大,默認是3個;設置須要根據Region大小肯定,一般能夠簡單的認爲hbase.hstore.compaction.max.size = RegionSize / hbase.hstore.compactionThreshold

8. Compaction是否消耗系統資源過多?

優化原理:Compaction是將小文件合併爲大文件,提升後續業務隨機讀性能,可是也會帶來IO放大以及帶寬消耗問題(數據遠程讀取以及三副本寫入都會消耗系統帶寬)。正常配置狀況下Minor Compaction並不會帶來很大的系統資源消耗,除非由於配置不合理致使Minor Compaction太過頻繁,或者Region設置太大狀況下發生Major Compaction。

觀察確認:觀察系統IO資源以及帶寬資源使用狀況,再觀察Compaction隊列長度,確認是否因爲Compaction致使系統資源消耗過多

優化建議:

(1)Minor Compaction設置:hbase.hstore.compactionThreshold設置不能過小,又不能設置太大,所以建議設置爲5~6;hbase.hstore.compaction.max.size = RegionSize / hbase.hstore.compactionThreshold

(2)Major Compaction設置:大Region讀延遲敏感業務( 100G以上)一般不建議開啓自動Major Compaction,手動低峯期觸發。小Region或者延遲不敏感業務能夠開啓Major Compaction,但建議限制流量;

(3)期待更多的優秀Compaction策略,相似於stripe-compaction儘早提供穩定服務

HBase列族設計優化

HBase列族設計對讀性能影響也相當重要,其特色是隻影響單個業務,並不會對整個集羣產生太大影響。列族設計主要從兩個方面檢查:

9. Bloomfilter是否設置?是否設置合理?

優化原理:Bloomfilter主要用來過濾不存在待檢索RowKey或者Row-Col的HFile文件,避免無用的IO操做。它會告訴你在這個HFile文件中是否可能存在待檢索的KV,若是不存在,就能夠不用消耗IO打開文件進行seek。很顯然,經過設置Bloomfilter能夠提高隨機讀寫的性能。

Bloomfilter取值有兩個,row以及rowcol,須要根據業務來肯定具體使用哪一種。若是業務大多數隨機查詢僅僅使用row做爲查詢條件,Bloomfilter必定要設置爲row,不然若是大多數隨機查詢使用row+cf做爲查詢條件,Bloomfilter須要設置爲rowcol。若是不肯定業務查詢類型,設置爲row。

優化建議:任何業務都應該設置Bloomfilter,一般設置爲row就能夠,除非確認業務隨機查詢類型爲row+cf,能夠設置爲rowcol

HDFS相關優化

HDFS做爲HBase最終數據存儲系統,一般會使用三副本策略存儲HBase數據文件以及日誌文件。從HDFS的角度望上層看,HBase便是它的客戶端,HBase經過調用它的客戶端進行數據讀寫操做,所以HDFS的相關優化也會影響HBase的讀寫性能。這裏主要關注以下三個方面:

10. Short-Circuit Local Read功能是否開啓?

優化原理:當前HDFS讀取數據都須要通過DataNode,客戶端會向DataNode發送讀取數據的請求,DataNode接受到請求以後從硬盤中將文件讀出來,再經過TPC發送給客戶端。Short Circuit策略容許客戶端繞過DataNode直接讀取本地數據。(具體原理參考此處)

優化建議:開啓Short Circuit Local Read功能。

11. Hedged Read功能是否開啓?

優化原理:HBase數據在HDFS中通常都會存儲三份,並且優先會經過Short-Circuit Local Read功能嘗試本地讀。可是在某些特殊狀況下,有可能會出現由於磁盤問題或者網絡問題引發的短期本地讀取失敗,爲了應對這類問題,社區開發者提出了補償重試機制 – Hedged Read。該機制基本工做原理爲:客戶端發起一個本地讀,一旦一段時間以後尚未返回,客戶端將會向其餘DataNode發送相同數據的請求。哪個請求先返回,另外一個就會被丟棄。

優化建議:開啓Hedged Read功能。

12. 數據本地率是否過低?

數據本地率:HDFS數據一般存儲三份,假如當前RegionA處於Node1上,數據a寫入的時候三副本爲(Node1,Node2,Node3),數據b寫入三副本是(Node1,Node4,Node5),數據c寫入三副本(Node1,Node3,Node5),能夠看出來全部數據寫入本地Node1確定會寫一份,數據都在本地能夠讀到,所以數據本地率是100%。如今假設RegionA被遷移到了Node2上,只有數據a在該節點上,其餘數據(b和c)讀取只能遠程跨節點讀,本地率就爲33%(假設a,b和c的數據大小相同)。

優化原理:數據本地率過低很顯然會產生大量的跨網絡IO請求,必然會致使讀請求延遲較高,所以提升數據本地率能夠有效優化隨機讀性能。數據本地率低的緣由通常是由於Region遷移(自動balance開啓、RegionServer宕機遷移、手動遷移等),所以一方面能夠經過避免Region無端遷移來保持數據本地率,另外一方面若是數據本地率很低,也能夠經過執行major_compact提高數據本地率到100%。

優化建議:避免Region無端遷移,好比關閉自動balance、RS宕機及時拉起並遷回飄走的Region等;在業務低峯期執行major_compact提高數據本地率

HBase讀性能優化概括

讀延遲較大無非三種常見的表象,單個業務慢、集羣隨機讀慢以及某個業務隨機讀以後其餘業務受到影響致使隨機讀延遲很大。瞭解完常見的可能致使讀延遲較大的一些問題以後,咱們將這些問題進行以下歸類,你們能夠在看到現象以後在對應的問題列表中進行具體定位:

file
file
file

寫優化

和讀相比,HBase寫數據流程卻是顯得很簡單:數據先順序寫入HLog,再寫入對應的緩存Memstore,當Memstore中數據大小達到必定閾值(128M)以後,系統會異步將Memstore中數據flush到HDFS造成小文件。
HBase數據寫入一般會遇到兩類問題,一類是寫性能較差,另外一類是數據根本寫不進去。這兩類問題的切入點也不盡相同,以下圖所示:
file

1. 是否須要寫WAL?WAL是否須要同步寫入?

優化原理:數據寫入流程能夠理解爲一次順序寫WAL+一次寫緩存,一般狀況下寫緩存延遲很低,所以提高寫性能就只能從WAL入手。WAL機制一方面是爲了確保數據即便寫入緩存丟失也能夠恢復,另外一方面是爲了集羣之間異步複製。默認WAL機制開啓且使用同步機制寫入WAL。首先考慮業務是否須要寫WAL,一般狀況下大多數業務都會開啓WAL機制(默認),可是對於部分業務可能並不特別關心異常狀況下部分數據的丟失,而更關心數據寫入吞吐量,好比某些推薦業務,這類業務即便丟失一部分用戶行爲數據可能對推薦結果並不構成很大影響,可是對於寫入吞吐量要求很高,不能形成數據隊列阻塞。這種場景下能夠考慮關閉WAL寫入,寫入吞吐量能夠提高2x~3x。退而求其次,有些業務不能接受不寫WAL,但能夠接受WAL異步寫入,也是能夠考慮優化的,一般也會帶來1x~2x的性能提高。

優化推薦:根據業務關注點在WAL機制與寫入吞吐量之間作出選擇

其餘注意點:對於使用Increment操做的業務,WAL能夠設置關閉,也能夠設置異步寫入,方法同Put相似。相信大多數Increment操做業務對WAL可能都不是那麼敏感~

2. Put是否能夠同步批量提交?

優化原理:HBase分別提供了單條put以及批量put的API接口,使用批量put接口能夠減小客戶端到RegionServer之間的RPC鏈接數,提升寫入性能。另外須要注意的是,批量put請求要麼所有成功返回,要麼拋出異常。

優化建議:使用批量put進行寫入請求

3. Put是否能夠異步批量提交?

優化原理:業務若是能夠接受異常狀況下少許數據丟失的話,還可使用異步批量提交的方式提交請求。提交分爲兩階段執行:用戶提交寫請求以後,數據會寫入客戶端緩存,並返回用戶寫入成功;當客戶端緩存達到閾值(默認2M)以後批量提交給RegionServer。須要注意的是,在某些狀況下客戶端異常的狀況下緩存數據有可能丟失。

優化建議:在業務能夠接受的狀況下開啓異步批量提交

使用方式:setAutoFlush(false)

4. Region是否太少?

優化原理:當前集羣中表的Region個數若是小於RegionServer個數,即Num(Region of Table) < Num(RegionServer),能夠考慮切分Region並儘量分佈到不一樣RegionServer來提升系統請求併發度,若是Num(Region of Table) > Num(RegionServer),再增長Region個數效果並不明顯。

優化建議:在Num(Region of Table) < Num(RegionServer)的場景下切分部分請求負載高的Region並遷移到其餘RegionServer;

5. 寫入請求是否不均衡?

優化原理:另外一個須要考慮的問題是寫入請求是否均衡,若是不均衡,一方面會致使系統併發度較低,另外一方面也有可能形成部分節點負載很高,進而影響其餘業務。分佈式系統中特別懼怕一個節點負載很高的狀況,一個節點負載很高可能會拖慢整個集羣,這是由於不少業務會使用Mutli批量提交讀寫請求,一旦其中一部分請求落到該節點沒法獲得及時響應,就會致使整個批量請求超時。所以不怕節點宕掉,就怕節點奄奄一息!

優化建議:檢查RowKey設計以及預分區策略,保證寫入請求均衡。

6. 寫入KeyValue數據是否太大?

KeyValue大小對寫入性能的影響巨大,一旦遇到寫入性能比較差的狀況,須要考慮是否因爲寫入KeyValue數據太大致使。KeyValue大小對寫入性能影響曲線圖以下:

file

圖中橫座標是寫入的一行數據(每行數據10列)大小,左縱座標是寫入吞吐量,右座標是寫入平均延遲(ms)。能夠看出隨着單行數據大小不斷變大,寫入吞吐量急劇降低,寫入延遲在100K以後急劇增大。

說到這裏,有必要和你們分享兩起在生產線環境由於業務KeyValue較大致使的嚴重問題,一塊兒是由於大字段業務寫入致使其餘業務吞吐量急劇降低,另外一起是由於大字段業務scan致使RegionServer宕機。

寫異常問題檢查點

上述幾點主要針對寫性能優化進行了介紹,除此以外,在一些狀況下還會出現寫異常,一旦發生須要考慮下面兩種狀況(GC引發的不作介紹):
Memstore設置是否會觸發Region級別或者RegionServer級別flush操做?

問題解析:以RegionServer級別flush進行解析,HBase設定一旦整個RegionServer上全部Memstore佔用內存大小總和大於配置文件中upperlimit時,系統就會執行RegionServer級別flush,flush算法會首先按照Region大小進行排序,再按照該順序依次進行flush,直至總Memstore大小低至lowerlimit。這種flush一般會block較長時間,在日誌中會發現「Memstore is above high water mark and block 7452 ms」,表示此次flush將會阻塞7s左右。

問題檢查點:

Region規模與Memstore總大小設置是否合理?若是RegionServer上Region較多,而Memstore總大小設置的很小(JVM設置較小或者upper.limit設置較小),就會觸發RegionServer級別flush。

列族是否設置過多,一般狀況下表列族建議設置在1~3個之間,最好一個。若是設置過多,會致使一個Region中包含不少Memstore,致使更容易觸到高水位upperlimit。

Store中HFile數量是否大於配置參數blockingStoreFile?

問題解析:對於數據寫入很快的集羣,還須要特別關注一個參數:hbase.hstore.blockingStoreFiles,此參數表示若是當前hstore中文件數大於該值,系統將會強制執行compaction操做進行文件合併,合併的過程會阻塞整個hstore的寫入。一般狀況下該場景發生在數據寫入很快的狀況下,在日誌中能夠發現」Waited 3722ms on a compaction to clean up ‘too many store files「

問題檢查點:
參數設置是否合理?hbase.hstore.compactionThreshold表示啓動compaction的最低閾值,該值不能太大,不然會積累太多文件,通常建議設置爲5~8左右。hbase.hstore.blockingStoreFiles默認設置爲7,能夠適當調大一些。

其餘

最後咱們講一講一些容易忽視的優化點:

使用壓縮

HBase支持大量的壓縮算法,能夠從嫘祖級別上進行壓縮。由於CPU壓縮和解壓縮消耗的時間每每比從磁盤讀取和寫入數據要快得多,因此使用壓縮一般會帶來很可觀的性能提高

file

你們能夠自行百度關於壓縮算法在HBase中的集成安裝,HBase包含一個可以測試壓縮設置是否正常的工具,咱們能夠輸入:

./bin/hbase org.apache.hadoop.hbase.util.CompresstionTest

進行檢測。

而後啓用檢查,由於即便測試工具報告成功了,因爲JNI須要先安裝好本地庫,若是缺失這一步將會在添加新服務器的時候出現問題,致使新的服務器使用本地庫打開含有壓縮列族的region失敗。

咱們能夠在服務器啓動的時候檢查壓縮庫是否已經正確安裝,若是沒有則不會啓動服務器:

<property>
    <name>hbase.regionserver.codecs</name>
    <value>snappy,lzo</value>
</property>

這樣一來region服務器在啓動的時候將會檢查Snappy和LZO壓縮庫是否已經正確安裝

咱們能夠經過shell建立表的時候指定列族的壓縮格式:

create 'testtable',{NAME => 'colfam1',COMPRESSION => 'GZ'}

須要注意的是,若是用戶要更改一個已經存在的表的壓縮格式,要先將該表disable才能修改以後再enable從新上線。而且更改後的region只有在刷寫存儲文件的時候纔會使用新的壓縮格式,沒有刷寫以前保持原樣,用戶能夠經過shell的major_compact 來強制格式重寫,可是此操做會佔用大量資源。

使用掃描緩存

若是HBase做爲一個MapReduce做業的而輸入源,最好將MapReduce做業的輸入掃描器實例的緩存用setCaching()設置爲比1大的多的值。例如設置爲500的時候則一次能夠傳送500行數據到客戶端進行處理。

限定掃描範圍

若是隻處理少數列,則應當只有這些列被添加到Scan的輸入中,由於若是沒有作篩選,則會掃描其餘的數據存儲文件。

關閉ResultScanner

這不會帶來性能提高,可是會避免一些性能問題。因此必定要在try/catch中關閉ResultScanner。

參考文檔

https://www.cnblogs.com/panfeng412/archive/2012/03/08/hbase-performance-tuning-section1.html
https://zhuanlan.zhihu.com/p/75630694
https://www.jianshu.com/p/77545e359e1e
https://blog.csdn.net/wsdc0521/article/details/108536492
https://blog.csdn.net/lw_ghy/article/details/60779222
https://blog.csdn.net/ourpush/article/details/53558292
http://www.javashuo.com/article/p-hinqdcwp-kb.html

歡迎關注,《大數據成神之路》系列文章

歡迎關注,《大數據成神之路》系列文章

歡迎關注,《大數據成神之路》系列文章

相關文章
相關標籤/搜索