本文對HBase開發及使用過程中遇到過的常見問題進行梳理總結,希望能解答新加入的HBaser們的一些疑惑。
1. HTable線程安全嗎?
HTable不是線程安全的,使用過程中建議一個線程中使用一個HTable對象,不同線程間不要共享HTable對象。
同時,為了提高客戶端的效率,不同的HTable對象公用同一個Configuration對象,共享HBase服務端的元數據信息,詳見HBase權威指南中有關HTable部分的介紹。
2. HTablePool該如何使用?
HBase 0.90 版本以前,使用HTablePool時通過getTable方法獲取HTable對象,使用完成后調用putTable方法將HTable對象放回到池中。
而HBase 0.90 以后的新版本中,使用完成后不再調用putTable方法,而是調用HTable的close方法將HTable對象放回到池中。
3. Scanner的Caching與Batch有什么區別?
caching是一次從服務端取到客戶端的記錄條數;而batch則是一次返回給客戶端(一個Result對象中)的KeyValue的個數。
舉個例子:如果每行記錄有5個KeyValue,而僅僅設置caching=10,假設scan表過程中表中匹配到的記錄數大於10條,那么一次next()操作從服務端返回的是10個Result,每個Result含有5個KeyValue:
* * * * *
* * * * *
* * * * *
* * * * *
* * * * *
* * * * *
* * * * *
* * * * *
* * * * *
* * * * *
而如果同時設置batch=2,那么一次next()操作將返回17個KeyValue:
* *
* *
*
* *
* *
*
* *
* *
*
* *
4. Put(List<Put> puts)效率一定更高嗎?
put(list)是用於提高吞吐量的。首先在不同region server之間是並行的;在同一個region server上的同一個region上也是並行的,而在不同region上則是串行的。
因為在同一個region server上,如果put(list)在一個region上執行,那么它是打包寫一條日志的,相當於並行寫入;而在不同region上執行話,它是一個for循環,而不是走線程池,所以是串行的。
5. Increment的正確性和性能靠譜嗎?
目前Increment還無法做到完全的正確性,在網絡出現timeout和region server發生failover的時候可能不正確,使用時需要根據應用場景慎重選擇。
至於Increment的性能,性能還不錯,尤其是在HBase 0.94和普通的Put寫操作差別不大,能達到每台region server 7000+。
6. Region個數越多越好嗎?
Region過多則影響flush效率和region server failover效率,還有就是對HDFS的壓力比較大;Region過少則對讀有影響,因為StoreFile數量比較多了,如果每個Region的StoreFile數量很少(線上集群一般維持在1.x~2.x個StoreFile),那么對讀操作無明顯影響。
寫入的話,Region多少影響不大,除非Region特別少並且寫壓力特別大,比如一個region server只有一個Region的特殊情況。
現在HBase 0.90版本每個region server建議3000個以內Region;而HBase 0.94版本則建議在1000個以內,幾百個就算很多了。
7. WAL操作日志的開銷有多大?
一般情況下,向region server服務端put數據時,如果開啟寫WAL日志的話,服務端大概會需要1ms~2ms的開銷。而如果不開啟WAL日志的話,服務端只有大概0.xms的開銷,基本上都是MemStore的內存操作。
另外,不管哪種情況下,對於一次put操作,都還需要加上網絡傳輸延遲RTT開銷(一般在0.5ms~1ms以內)。
8. 單表單Region的寫入性能有多高?
不考慮任何優化的前提下,Java API在WAL開啟的情況下每秒能達到800左右 tps,關閉WAL則能達到1000+ tps,基本上就是網絡速度的上限;而Thrift接口大概有10~20%的性能損失,實際測試顯示在網絡RTT=0.7ms的環境下,能達到每秒550左右tps;在網絡RTT=2.0ms的情況下,則只能達到350左右tps。
以上的寫入性能數據,與HBase的實際寫入性能相差甚遠,因為沒有考慮進行優化,實際應用中可以從預分region、多客戶端、多線程、批量寫入等方式使每個region server達到性能極限。
注意:單表單region的情況下,短時間內如果低並發寫入沒有問題,而如果高並發寫入,則寫一會之后可能會由於發生region split而導致請求被block住。
9. 單Region Server的寫入性能有多高?
如果要壓測單個region server的寫入能力,那么可以新建一張測試表,同時預先創建多個region(例如:10~50個),然后隨機生成rowkey和value寫入到HBase集群進行壓力測試,最終測試結果除以HBase集群內region server的個數,就可以大概得到單個region server的寫入性能值了。
從HBase集群測試團隊得到的結果,對於16核CPU,24GB內存的region server機器(DataNode進程分配1GB內存,HBase RegionServer進程分配16GB內存),不開WAL的話,單region server可以達到3w以上tps;開啟WAL的話,一般單region server能達到9k~2w tps。而HBase的Thrift接口,可以達到Native Java API 80%~90%左右的性能。
10. Rowkey中包含時間戳導致空Region有什么問題?
假設rowkey中包含時間戳,同時設置了TTL,自動刪除過期數據,那么隨着時間戳值的增長,會導致過期數據已經被刪除,但是空的region還存在,過多的region會影響flush效率和region server failover效率,還有就是對HDFS的壓力比較大;同時由於過多空region也會占用一些元數據信息。
解決這個問題,一般有兩個方法:
1)按時間周期新建不同的表:例如按天建不同的表,跨天時切換表進行讀寫,該方法的缺點是每天都需要建表,由於DDL事務都是master做的,只要master出問題就容易影響事務,一般來說為了防止受master影響,需要提前幾天把表建好。
2)將時間戳字段進行處理:rowkey中不直接存儲當前的時間戳timestamp,而改為存儲自當周周一凌晨00:00:00開始累計的時間戳值(秒或毫秒等均可),這樣表中最多存儲一周數據對應的region數,當下周開始后就開始復用之前的region,從而避免了region的膨脹。相應地,查詢端也需要對時間戳timestamp進行響應的處理。考慮到擴展性,假設要保存的數據超過一周時間,那么該方法也可以從1周擴展到1個月進行適應。
{{持續更新中}}