提升HBase數據庫寫入性能
調整參數
入門級的調優可以從調整參數開始。投入小,回報快。
1. Write Buffer Size
快速配置
Java代碼
- HTable htable = new HTable(config, tablename);
- htable.setWriteBufferSize(6 * 1024 * 1024);
- htable.setAutoFlush(false);
設置buffer的容量,例子中設置了6MB的buffer容量。
* 必須禁止auto flush。
* 6MB是經驗值,可以上下微調以適應不同的寫場景。
原理
HBase Client會在數據累積到設置的閾值后才提交Region Server。這樣做的好處在于可以減少RPC連接次數。
2. RPC Handler
快速配置
修改hbase-site.xml的hbase.regionserver.handler.count配置項:
Xml代碼
- <property>
- <name>hbase.regionserver.handler.count</name>
- <value>100</value>
- </property>
原理
該配置定義了每個Region Server上的RPC Handler的數量。Region Server通過RPC Handler接收外部請求并加以處理。所以提升RPC Handler的數量可以一定程度上提高HBase接收請求的能力。當然,handler數量也不是越大越好,這要取決于節點的硬件情況。
3. Compression
快速配置
Java代碼
- HColumnDescriptor hcd = new HColumnDescriptor(familyName);
- hcd.setCompressionType(Algorithm.SNAPPY);
原理
數據量大,邊壓邊寫也會提升性能的,畢竟IO是大數據的最嚴重的瓶頸,哪怕使用了SSD也是一樣。眾多的壓縮方式中,推薦使用SNAPPY。從壓縮率和壓縮速度來看,性價比最高。
4. WAL
快速配置
- Put put = new Put(rowKey);
- put.setWriteToWAL(false);
原理
其實不推薦關閉WAL,不過關了的確可以提升性能...因為HBase在寫數據前會先把操作持久化在WAL中,以保證在異常情況下,HBase可以按照WAL的記錄來恢復還未持久化的數據。
5. Replication
雖然推薦replica=3,不過當數據量很夸張的時候,一般會把replica降低到2。當然也不推薦隨便降低replica。
6. Compaction
在插數據時,打開HMaster的web界面,查看每個region server的request數量。確保大部分時間,寫請求在region server層面大致平均分布。在此前提下,我們再考慮compaction的問題。繼續觀察request數量,你會發現在某個時間段,若干region server接收的請求數為0(當然這也可能是client根本沒有向這個region server寫數據,所以之前說,要確保請求在各region server大致平均分布)。這很有可能是region server在做compaction導致。compaction的過程會block寫。 優化的思路有兩種,一是提高compaction的效率,二是減少compaction發生的頻率。
提高以下兩個屬性的值,以增加執行compaction的線程數:
hbase.regionserver.thread.compaction.large
hbase.regionserver.thread.compaction.small
推薦設置為2。
優化Client設計
以上都是些常見的參數調整。但是寫性能差一般是源于Client端的糟糕設計。
1. 避免region split
不得不說,region split是提升寫性能的一大障礙。減少region split次數可以從兩方面入手。首先是預分配region。
預分配region
不在此重復region split的原理,請參見http://blog.sina.com.cn/s/blog_9cee0fd901018vu2.html。按數據量,row key的規則預先設計并分配好region,可以大幅降低region split的次數, 甚至不split。這點非常重要。
適當提升hbase.hregion.max.filesize
提升region的file容量也可以減少split的次數。具體的值需要按照你的數據量,region數量,row key分布等情況具體考量。一般來說,3~4G是不錯的選擇。
2. 均勻分布每個Region Server的寫壓力
之前也提到了RPC Handler的概念。好的Data Loader需要保證每個RPC Handlder都有活干,每個handler忙,但不至超載。注意region的壓力不能過大,否則會導致反復重試,并伴有超時異常(可以提高超時的時間設置)。
如何保證每個Region Server的壓力均衡呢?這和region 數量,startKey設計, client數據插入順序有關。
一般來說,簡單的數據插入程序應該是多線程實現。讓每個線程負責一部分的row key范圍,而row key范圍又和region相關,所以可以在數據插入時,程序控制每個region的壓力,不至于有些region閑著沒事干。
那么,如何設計row key呢?舉個比較實際的例子,如果有張HBase表來記錄每天某城市的通話記錄, 常規思路下的row key是由電話號碼 + yyyyMMddHHmmSS + ... 組成。按電話號碼的規律來劃分region。但是這樣很容易導致數據插入不均勻(因為電話通話呈隨機性)。但是,如果把電話號碼倒序,數據在region層面的分布情況就大有改觀。
3. 分布式的數據插入程序
HBase客戶端在單節點上運行,即使使用多線程,也受限于單節點的硬件資源,寫入速度不可能很快。典型的思路是將客戶端部署在多個節點上運行,提高寫的并發度。MapReduce是個很好的選擇。使用MapReduce把寫入程序分布到集群的各個節點上,并在每個mapper中運行多線程的插入程序。這樣可以很好的提高寫并發度。
注意,不要使用reducer。mapper到reducer需要走網絡,受限于集群帶寬。其次,實際的應用場景一般是用戶從關系型數據庫中導出了文本類型的數據,然后希望能把導出的數據寫到HBase里。在這種情況下,需要小心謹慎地設計和實現file split邏輯。
4. HBase Client太慢?BulkLoad!
請拿出HBase的API讀讀,HFileOutputFomart里有個叫configureIncrementalLoad的方法。API是這么介紹的:
Configure a MapReduce Job to perform an incremental load into the given table. This
Inspects the table to configure a total order partitioner
Uploads the partitions file to the cluster and adds it to the DistributedCache
Sets the number of reduce tasks to match the current number of regions
Sets the output key/value class to match HFileOutputFormat's requirements
Sets the reducer up to perform the appropriate sorting (either KeyValueSortReducer or PutSortReducer)
The user should be sure to set the map output value class to either KeyValue or Put before running this function.
這是HBase提供的一種基于MapReduce的數據導入方案,完美地繞過了HBase Client(上一節的分布式插入方法也是用mapreduce實現的,不過本質上還是用hbase client來寫數據)
網上有不少文章敘述了使用命令行方式運行BulkLoad,比如
但是,不得不說,實際生產環境上很難使用這種方式。畢竟源數據不可能直接用來寫HBase。在數據遷移的過程中會涉及到數據清洗、整理歸并等許多額外的工作。這顯然不是命令行可以做到的事情。按照API的描述, 可行的方案是自定義一個Mapper在mapper中清洗數據,Mapper的輸出value為HBase的Put類型,Reducer選用PutSortReducer。然后使用HFileOutputFormat#configureIncrementalLoad(Job, HTable);解決剩余工作。
不過,這種實現也存在局限性。畢竟Mapper到Reducer比較吃網絡。
至此,本文介紹了三種HBase數據寫入的方法(1種多線程,2種mapreduce),并介紹了性能調優的方法。希望能對大家有所幫助。本文提供的所有數據導入方法,作者均親手實現并使用TB級數據測試。限于篇幅,在此只提供實現思路。
原文鏈接:http://joshuasabrina.iteye.com/blog/1798239
【編輯推薦】