淺談HBase讀寫優化
Labs 導讀
HBase是一種分布式的、面向列的開源數據庫,底層基于LSM樹構建實現,通過順序寫操作,寫性能大幅提升,讀取時需要將內存中的數據和磁盤中的數據合并,犧牲了一部分讀性能,適用于寫多讀少的場景。
Part 01、 讀寫流程
RegionServer是HBase系統中最核心的組件,主要負責用戶數據寫入、讀取等基礎操作,其內部結構如下所示:
圖片
HBase通過Client連接RegionServer進行數據讀寫,一張表會被水平切分成多個Region,每個Region負責自己區域的數據讀寫請求。一個Region由多個Store組成,每個Store存放對應列簇的數據,比如一個表中有兩個列簇,這個表的所有Region就都會包含兩個Store。
HBase數據從RegionServer的讀寫位置,在HBase0.96版本后,只依賴于hbase:meta表,hbase:meta表存儲了所有用戶HRegion的位置信息,hbase:meta的一個rowkey就對應一個Region,meta表只有一個列簇info,每一行數據又分為4列,如下所示。
圖片
每條MetaData的數據信息約1KB左右,假如HRegion設置為2GB,可以支持2^21個Region,最多可以支持存儲4PB的數據,對于一般的集群來說已經夠用。Meta表在整個HBase集群中只會存在一個,不會分裂split,位置在ZooKeeper的/hbase/meta-region-server節點上,在第一次讀取后緩存在客戶端。HBase讀寫優化,需要從RegionServer和Client端同時進行優化,分析讀寫流程,資源消耗,以及參數調優配置。
Part 02、 寫性能優化
先簡要分析下HBase數據寫入的流程,如下圖所示:
圖片
當客戶端發起一個Put請求時,首先它從hbase:meta表中查出該Put數據最終需要去的HRegionServer。然后客戶端將Put請求發送給相應的HRegionServer,在HRegionServer中它首先會將該Put操作寫入WAL日志文件中(Flush 到磁盤中)。
寫完WAL日志文件后,HRegionServer根據Put中的TableName和RowKey找到對應的HRegion,并根據Column Family找到對應的HStore,并將Put寫入到該HStore的MemStore中。此時寫成功,并返回通知客戶端。
在MemStore Flush過程中,還會在尾部追加一些meta數據,其中就包括Flush時最大的WAL Sequence值,以告訴HBase這個StoreFile寫入的最新數據的序列,那么在Recover時就直到從哪里開始。在HRegion啟動時,這個sequence會被讀取,并取最大的作為下一次更新時的起始Sequence。
在HBase數據寫入的過程中,會遇到寫性能較差、數據根本寫入異常問題,可以考慮從下圖的思路進行優化:
圖片
2.1 客戶端寫優化
2.1.1 WAL寫入優化
數據寫入流程可以理解為一次順序寫WAL(Write Ahead Log)加上一次寫緩存,如果業務上能夠忍受小分部數據丟失,且需要極限提高寫入速度,可以考慮禁用WAL,缺點就是系統crash的時候會丟一部分數據,且無法做跨集群的replication。WAL 的持久化分為四個等級:
● SKIP_WAL:只寫緩存不寫HLog日志,數據有丟失的風險。
● ASYNC_WAL:異步將數據寫入HLog日志中。
● SYNC_WAL:同步將數據寫入日志文件中,并沒有真正落盤。
● FSYNC_WAL:同步將數據寫入日志文件并強制落盤。
默認如果用戶沒有指定持久化等級,HBase使用SYNC_WAL等級持久化數據,可根據業務關注點,在WAL機制和寫入吞吐量之間作出選擇,用戶可以通過客戶端設置WAL持久化策略。除了在創建表的時候直接設置WAL存儲級別,也可以通過客戶端設置WAL持久化等級,put.setDurability(Durability.SYNC_WAL);
2.1.2 PUT批量優化
HBase分別提供了單條PUT以及批量PUT的API接口,使用批量PUT接口可以減少客戶端到RegionServer之間的RPC連接數,提高寫入吞吐量。如果對數據實時性要求不是特別嚴格,可以考慮開啟異步批量提交,用戶可以設置setAutoFlush(false),客戶端緩存達到閾值(默認2M)后批量提交給RegionServer。
能夠減少RPC調用的次數,將數據從client端提交給server端的任務交給HBase來處理,提高吞吐量;缺點是如果客戶端異常,緩存數據可能丟失。
2.1.3 大KeyValue優化
KeyValue大小對寫入性能影響巨大。如果太大,會對性能產生很大的影響,會導致集群寫入忽然變慢、數據堆積,影響集群整體的業務。
RowKey的最大長度限制為64KB,但在實際應用中最多不會超過100B。這是由于HBase的Rowkey會按照rowkey+columnFamily+qualifier+timestamp組成的cell被多次冗余存儲,RowKey越大,浪費的內存和硬盤資源也會越多。Value過大也會對性能產生很大的影響,也會影響到HBase的響應速度。一般有下面的2種解決方法:
● Value過大,建議拆成多列存儲,每次返回需要的值或者將Value存儲到HDFS上,在HBase中存儲URL。
● 使用HBase2.0后的MOB特性,將Meta數據和MOB數據分開放到不同的文件中,存儲文檔、圖片等二進制數據有極佳的性能。
2.1.4 Bulkload導入優化
對于離線導入數據的業務場景,可使用Bulkload導入。Bulkload是一個MapReduce程序,輸出HFile文件,雖然實時性差,但是吞吐量大,效率高,可減少對HBase服務器壓力,提升集群整體的性能。
2.2 服務端寫優化
2.2.1 Region數量過少優化
通過業務的數據量大小預估Region分區,在建表時進行預分區,達到充分利用多server并行處理的能力。在預分區如果發現部分Region負載以及請求量不均勻,需要切分部分請求到負載高的Region,然后等待HBase集群進行負載均衡。如果想立刻解決,則可以使用命令將部分Region遷移到其他RegionServer節點上,以達到充分利用服務器資源,負載均衡。
2.2.2 寫入請求均衡優化
檢查RowKey設計以及預分區策略,保證寫入請求均衡。針對Get查詢為主的表,可以使用Hash預分區策略;針對Scan為主的表,可使用分段預分區的策略。
2.2.3 使用SSD存儲WAL優化
影響寫的性能就是WAL的寫,SSD能很大的降低其響應時間,將WAL文件寫到SSD上,對于寫性能會有非常大的提升。使用HDFS Archival Storage機制,配置HDFS的部分文件目錄為SSD介質。hbase.wal.storage.policy默認為none,用戶可以指定ONESSD(WAL一個副本寫入SSD介質)或者ALLSSD(WAL的三個副本全部寫入SSD介質)。
Part 03、 讀性能優化
HBase數據查詢鏈路,相對寫鏈路比較復雜,在HBase寫數據時,相同的Cell(RowKey /ColumnFamily /Column 相同)并不保證在一起,刪除一個Cell也只是寫入一個新的Cell,標記為Delete,需要從BlockCache、MemStore、StoreFile(HFile)中依次掃描,再將將結果合并即可(Merge Read),流程如下圖所示:
圖片
其中StoreFile的掃描,先會使用Bloom Filter過濾那些不可能符合條件的HFile,然后使用Block Index快速定位Cell,并將其加載到BlockCache中,然后從BlockCache中讀取。我們知道一個HStore可能存在多個StoreFile(HFile),此時需要掃瞄多個HFile,如果HFile過多會引起性能問題。在HBase數據查詢的過程,會遇到數據查詢過慢問題,可從下圖思路進行優化:
圖片
3.1客戶端讀優化
3.1.1 Get/Scan讀請求優化
對于Get使用批量請求,HBase分別提供了單條Get以及批量Get的API接口,使用批量Get接口可以減少客戶端到RegionServer之間的RPC連接數,提高讀取吞吐量。
對于Scan設置客戶端緩存,在HBase總RPC次數調整到比較合理的前提下,可以考慮將大Scan場景下將Scan緩存從100增大到500或者1000,用以減少RPC次數。
3.1.2指定列簇或列優化
在客戶端查詢時盡量指定列簇或者列進行精確查詢,過濾不必要的列族或者列,減少Region的數據查詢和網絡數據傳輸。
3.1.3離線讀禁止緩存優化
離線批量讀取請求設置禁用緩存,scan.setCacheBlocks(false),適用于離線的全表掃秒,如MapReduce,此時使用緩存不僅無法提升性能,可能還會適得其反。
3.1.4布隆過濾器使用優化
在任何業務都應該設置布隆過濾器,用空間換取時間。默認設置為row,除非確定業務隨機查詢類型為row+column,這是布隆過濾器設置為rowcol(適合大量指定column的場景,這種場景下占用的緩存內存以及磁盤的量會增加)。
3.2服務端讀優化
3.2.1讀請求負載均衡優化
對于數據吞吐量較大,且一次查詢返回的數據量較大的場景,則Rowkey必須進行散列化處理,同時建表必須進行預分區處理。針對Get查詢為主的表,可以使用Hash預分區策略,表數據均勻分布;針對Scan掃描為主的表,可使用分段預分區的策略,在兼顧業務場景的情況下,設計Rowkey,在滿足查詢需求的前提下盡量對數據打散并進行負載均衡。
3.2.2 BlockCache緩存優化
如果JVM內存配置量小于20G,BlockCache策略選擇LRUBlockCache;否則選擇 BucketCache策略的offhea模式。如果是offheap模式,也可以根據業務場景的讀寫比例來配置堆中讀寫heap的比例,默認堆中讀寫緩存均占heap的40%,即讀寫均衡。
3.2.3 HFile數量控制優化
一個Store中包含多個HFile文件,文件越多檢索所需的IO次數越多,讀取延遲也越高。文件數量通常取決于minorCompaction的執行策略,一般和兩個配置參數有關hbase.hstore.compactionThreshold 和 hbase.hstore.compaction.max.size,前者表示一個store中的文件數超過閾值就應該進行合并;后者表示參與合并的文件大小最大是多少,超過此大小的文件不能參與合并。可以查看RegionServer級別以及Region級別的HFile數量,確認HFile文件是否過多。hbase.hstore.compactionThreshold設置不能太大,默認為3個。
3.2.4 MajorCompaction優化
MajorCompaction可將一個Store下的所有文件合并成一個,并在合并的過程中將修改和刪除的數據一共處理完成,釋放硬盤資源。由于配置文件中默認的MajorCompaction是定時按表執行,且消耗資源很大,對系統性能影響同樣很大,所以對于讀取延遲以及系統性能波動敏感的業務通常不建議開啟自動MajorCompaction,而是利用腳本定時或者手動在業務低峰期觸發;對于延遲不敏感的業務可以開啟自動MajorCompaction,但是建議限制流量。
3.2.5 數據本地化
Hbase的數據在寫的時候是本地化,但是當Region被遷移的時候,數據可能就不再滿足本地化性了,直到完成Compaction,才能恢復數據本地化。盡量避免Region無故遷移。對于本地化率較低的節點,可以在業務低峰期執行MajorCompaction。
Part 04、 總結
HBase讀寫的優化,需要考慮業務的使用場景,預先評估好集群的合理規模,對讀寫的場景進行資源消耗量化分析,從而更好的進行RowKey設計,對Region的預分區,盡量將數據分散到各個Region上,保證讀寫請求均衡,降低Compactiont對業務的影響,降低數據存儲容量和網絡資源消耗。在HBase眾多配置參數中,選擇合理的配置組合,達到讀寫的最優配置。