1. 程式人生 > >實時系統HBase讀寫優化--大量寫入無障礙

實時系統HBase讀寫優化--大量寫入無障礙

在使用hbase過程中發現在寫入hbase的資料量很大時,經常發生寫不進去的情況。而我們基於hbase的應用是對實時性要求很高的,一旦hbase不能讀寫則會大大影響系統的使用。下面將記錄hbase寫優化的過程。

1.禁止Major Compaction

在hbase進行Major Compaction時,該region將合併所有的storefile,因此整個region都不可讀,所有對此region的查詢都會block。HBase預設一天左右執行一次Major Compaction。我們將Major Compaction禁掉並用Cron指令碼每天在系統空閒時對所有表執行major compaction。

Major Compaction的配置:

  1. <spanstyle="font-size:18px;"><property>
  2. <name>hbase.hregion.majorcompaction</name>
  3. <value>0</value>
  4. </property></span>

預設是1天,每個region會在建立時以當前時間初始化regionMajorCompactionTime,並將下一次的major compaction時間設為1+-0.2天。配置中將此值設為0禁止major compaction。

major_compaction的指令碼:取出所有table,一一執行major_compact:

  1. <span style="font-size:18px;">TMP_FILE=tmp_tables  
  2. TABLES_FILE=tables.txt  
  3. echo "list" | hbase shell > tmp_tables  
  4. sleep 2
  5. sed '1,6d' $TMP_FILE | tac | sed '1,2d' | tac > $TABLES_FILE  
  6. sleep 2
  7. for table in $(cat $TABLES_FILE); 
    do
  8.         echo "major_compact '$table'" | hbase shell  
  9.         sleep 10
  10. done</span>  
2.禁掉split

hbase通過split region實現水平的sharding,但在split的過程中舊的region會下線,新region還會做compaction,中間有一段時間大量的資料不能被讀寫,這對於我們這種online系統是不能忍受的。我們同樣禁掉自動的split,而在晚上系統空閒時執行我們的splittool手動的split。

禁止split的配置:

  1. <spanstyle="font-size:18px;"><property>
  2.  <name>hbase.hregion.max.filesize</name>
  3.  <value>536870912000</value>
  4.  </property></span>
配置項的含義是當region的大小大於設定值後hbase就會開始split,我們將此值設為500G,我們認為在白天系統繁忙時一個region不會超過此大小,在晚上時執行splittool將region分割開。

splittool的邏輯比較簡單。遍歷所有region的資訊,如果region大小大於某值(比如1G)則split該region,這樣為一輪split,如果一輪後沒有大於某值的region則結束,如果還有大於某個值的region則繼續新一輪split,直到沒有region大於某個閾值為止。這裡提一下判斷split完成的方法:通過檢查hdfs上舊region的資料夾是否被清除來判斷split是否結束。

3.設定blockingStoreFiles

這個引數的重要性是在我們的效能測試中發現的。我們禁掉major_compaction和split後理論上寫入應該無障礙了,但在測試中發現寫入單個region速度大於10M/s時還是會出現長時間無法寫入的情況。通過檢視log,我們發現了這行log“Waited 90314ms on a compaction to clean up 'too many store  files'”,通過檢視程式碼發現原來是blockingStoreFiles這個引數在作怪。

在flushRegion時會檢測當前store中hfile的數量是否大於此值,如果大於則會block資料的寫入,等待其他執行緒將hfile compact掉。這樣,如果寫入速度超過compact的速度,hbase就會阻止該region的資料寫入。

  1. <span style="font-size:18px;">privateboolean flushRegion(final FlushRegionEntry fqe) {  
  2.     HRegion region = fqe.region;  
  3.     if (!fqe.region.getRegionInfo().isMetaRegion() &&  
  4.         isTooManyStoreFiles(region)) {  
  5.       if (fqe.isMaximumWait(this.blockingWaitTime)) {  
  6.         LOG.info("Waited " + (System.currentTimeMillis() - fqe.createTime) +  
  7.           "ms on a compaction to clean up 'too many store files'; waited " +  
  8.           "long enough... proceeding with flush of " +  
  9.           region.getRegionNameAsString());  
  10.       } </span>  
預設值為7
  1. <span style="font-size:18px;">this.blockingStoreFilesNumber =  
  2.       conf.getInt("hbase.hstore.blockingStoreFiles"7);  
  3.     if (this.blockingStoreFilesNumber == -1) {  
  4.       this.blockingStoreFilesNumber = 1 +  
  5.         conf.getInt("hbase.hstore.compactionThreshold"3);  
  6.     }</span>  
我們將此值設為很大的值,使得此問題不會block我們的寫入。
  1. <spanstyle="font-size:18px;"><property>
  2. <name>hbase.hstore.blockingStoreFiles</name>
  3. <value>2100000000</value>
  1. </property></span>
http://blog.csdn.net/mrtitan/article/details/8660280