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