簡介
在項目開發過程中,我們經常需要一些benchmark工具來對系統進行壓測,以獲得系統的性能參數,極限吞吐等等指標。
而在HBase中,就自帶了一個benchmark工具—PerformanceEvaluation,可以非常方便地對HBase的Put、Get、Scan等API進行性能測試,並提供了非常豐富的參數來模擬各種場景。
這篇文章,就以HBbase2.0中的PerformanceEvaluation工具為例,給大家講解一下這款HBase benchmark工具的使用和注意事項。
參數介紹
PerformanceEvaluation的全名是org.apache.hadoop.hbase.PerformanceEvaluation. 已經集成在了bin/hbase工具集中。
在安裝好HBase的機器上,在HBase的安裝路徑的bin目錄下執行hbase pe,加上相應參數,即可運行PE工具(以下簡稱PerformanceEvaluation為PE)。
如果不加任何參數,則會輸出PE的幫助信息。
[root@xxxxxx ~]# hbase pe Usage: java org.apache.hadoop.hbase.PerformanceEvaluation \ <OPTIONS> [-D<property=value>]* <command> <nclients> General Options: nomapred 采用MapReduce的方式啟動多線程測試還是通過多線程的方式,如果沒有安裝MapReduce,或者不想用MapReduce,通常我們采用多線程的方式,因此一般在命令中加上--nomapred來表示不使用MapReduce。 rows 每個客戶端(線程)運行的行。默認值:一百萬。注意這里的行數是指單線程的行數,如果rows=100, 線程數為10,那么在寫測試中,寫入HBase的將是 100 x 10 行 size 總大小,單位GiB。與--rows互斥。默認值:1.0。 sampleRate 樣本比例:對總行數的一部分樣本執行測試。只有randomRead支持。默認值:1.0 traceRate 啟用HTrace跨度。每N行啟動一次跟蹤。默認值:0 table 測試表的名字,如果不設,默認為TestTable。 multiGet 如果> 0,則在執行RandomRead時,執行多次獲取而不是單次獲取。默認值:0 compress 要使用的壓縮類型(GZ,LZO,...)。默認值:'無' flushCommits 該參數用於確定測試是否應該刷新表。默認值:false writeToWAL 在puts上設置writeToWAL。默認值:True autoFlush 默認為false,即PE默認用的是BufferedMutator,BufferedMutator會把數據攢在內存里,達到一定的大小再向服務器發送,如果想明確測單行Put的寫入性能,建議設置為true。個人覺得PE中引入autoFlush會影響統計的准確性,因為在沒有攢夠足夠的數據時,put操作會立馬返回,根本沒產生RPC,但是相應的時間和次數也會被統計在最終結果里。 oneCon 多線程運行測試時,底層使用一個還是多個鏈接。這個參數默認值為false,每個thread都會啟一個Connection,建議把這個參數設為True presplit 表的預分裂region個數,在做性能測試時一定要設置region個數,不然所有的讀寫會落在一個region上,嚴重影響性能 inmemory 試圖盡可能保持CF內存的HFile。不保證始終從內存中提供讀取。默認值:false usetags 與KV一起寫標簽。與HFile V3配合使用。默認值:false numoftags 指定所需的標簽號。僅當usetags為true時才有效。 filterAll 通過不將任何內容返回給客戶端,幫助過濾掉服務器端的所有行。通過在內部使用FilterAllFilter,幫助檢查服務器端性能。 latency 設置為報告操作延遲。默認值:False bloomFilter Bloom 過濾器類型,[NONE,ROW,ROWCOL]之一 valueSize 寫入HBase的value的size,單位是Byte,大家可以根據自己實際的場景設置這個Value的大小。默認值:1024 valueRandom 設置是否應該在0和'valueSize'之間改變值大小;設置讀取大小的統計信息:默認值: Not set. valueZipf 設置是否應該以zipf格式改變0和'valueSize'之間的值大小, 默認值: Not set. period 報告每個'period'行:默認值:opts.perClientRunRows / 10 multiGet 批處理組合成N組。只有randomRead支持。默認值: disabled replicas 啟用區域副本測試。默認值:1。 splitPolicy 為表指定自定義RegionSplitPolicy。 randomSleep 在每次獲得0和輸入值之前進行隨機睡眠。默認值:0 Note: -D properties will be applied to the conf used. For example: -Dmapreduce.output.fileoutputformat.compress=true -Dmapreduce.task.timeout=60000 Command: filterScan 使用過濾器運行掃描測試,根據它的值查找特定行(確保使用--rows = 20) randomRead 運行隨機讀取測試 randomSeekScan 運行隨機搜索和掃描100測試 randomWrite 運行隨機寫測試 scan 運行掃描測試(每行讀取) scanRange10 使用開始和停止行(最多10行)運行隨機搜索掃描 scanRange100 使用開始和停止行運行隨機搜索掃描(最多100行) scanRange1000 使用開始和停止行(最多1000行)運行隨機搜索掃描 scanRange10000 使用開始和停止行運行隨機搜索掃描(最多10000行) sequentialRead 運行順序讀取測試 sequentialWrite 運行順序寫入測試 Args: nclients 整數。必須要有該參數。客戶端總數(和HRegionServers) running: 1 <= value <= 500 Examples: 運行一個單獨的客戶端: $ bin/hbase org.apache.hadoop.hbase.PerformanceEvaluation sequentialWrite 1
PE工具的參數非常多,很多參數只是用於某項專門的測試。這里我只介紹一下比較重要的幾個全局參數。
- nomapred 采用MapReduce的方式啟動多線程測試還是通過多線程的方式,如果沒有安裝MapReduce,或者不想用MapReduce,通常我們采用多線程的方式,因此一般在命令中加上--nomapred來表示不使用MapReduce。
- oneCon 多線程運行測試時,底層使用一個還是多個連接。這個參數默認值為false,每個thread都會啟一個Connection,建議把這個參數設為True,至於原因,后面的章節會講。
- valueSize 寫入HBase的value的size,單位是Byte,大家可以根據自己實際的場景設置這個Value的大小。
- blockEncoding PE工具會自動建表,這個參數用來指定表的block encoding。關於encoding后面會有專門的文章介紹,這里不再講。
- table 測試表的名字,如果不設,默認為TestTable。
- rows 總共測試的行數。注意這里的行數是指單線程的行數,如果rows=100, 線程數為10,那么在寫測試中,寫入HBase的將是 100 x 10 行。
- size 總測試的數據大小,單位為GB,這個參數與上面的size是互斥的,不要兩個參數一起設。在使用randomReads和randomSeekScans測試時,這個size可以用來指定讀取的數據范圍。這個值在Read時非常重要,如果設的不好,會產生很多返回值為空的讀,影響測試結果,下面會詳細介紹。
- compress 設置表的compress算法,根據自己選擇,默認是None,即不做壓縮。
- presplit 表的預分裂region個數,在做性能測試時一定要設置region個數,不然所有的讀寫會落在一個region上,嚴重影響性能
- autoFlush 默認為false,即PE默認用的是BufferedMutator,BufferedMutator會把數據攢在內存里,達到一定的大小再向服務器發送,如果想明確測單行Put的寫入性能,建議設置為true。個人覺得PE中引入autoFlush會影響統計的准確性,因為在沒有攢夠足夠的數據時,put操作會立馬返回,根本沒產生RPC,但是相應的時間和次數也會被統計在最終結果里。
比較重要的參數就這么多,其他的參數要么使用默認就好,要么就是和具體的測試命令相關,用戶可以根據測試的內容具體設置。
使用示例
下面我用測試讀和寫兩個示例來講解下PE工具的使用
隨機寫測試 RandomWriteTest
RandomWriteTest常用來評估HBase的寫性能。使用的命令如下:
hbase pe --nomapred --oneCon=true --valueSize=100 --compress=SNAPPY --rows=150000 --autoFlush=true --presplit=64 randomWrite 64
在這個測試中,我把PE模式設為了非MapReduuce(--nomapred),即采用起線程的形式。跑的命令是randomWrite,即隨機寫入、后面跟的64代表起了64個線程來做寫入。
--rows=150000 代表每個線程會寫入150000行數據。其他的參數含義可以參見之前的章節。每次測試都會刪除之前測試創建的測試表。刪除表的時間不計入結果。
PE工具的所有的輸出都會直接寫到LOG文件,LOG的位置需要參照HBase的設置。運行結束后,PE會分別打出每個線程的延遲狀況。如下面是其中一個線程的結果:
2018-05-18 12:07:23,282 INFO [TestClient-11] hbase.PerformanceEvaluation(475): Latency (us) : mean=2516.36, min=872.00, max=73776.00, stdDev=1978.60, 50th=2304.00, 75th=2605.00, 95th=3418.00, 99th=790 8.00, 99.9th=34241.00, 99.99th=73263.00, 99.999th=73776.00 2018-05-18 12:07:23,282 INFO [TestClient-11] hbase.PerformanceEvaluation(475): Num measures (latency) : 150000 2018-05-18 12:07:23,283 INFO [TestClient-11] hbase.PerformanceEvaluation(475): Mean = 2516.36 Min = 872.00 Max = 73776.00 StdDev = 1978.60 50th = 2304.00 75th = 2605.00 95th = 3418.00 99th = 7908.00 99.9th = 34241.00 99.99th = 73263.00 99.999th = 73776.00
PE統計了這個線程一共跑了多少行,和相應的延遲統計,包括min,max,999th延遲等等。
並在最后統計了所有線程的最大持續時間,平均持續時間等等。
2018-05-18 12:07:25,564 INFO [main] hbase.PerformanceEvaluation(507): [RandomWriteTest duration ] Min: 36969ms Max: 40160ms Avg: 38203ms
比較坑的是,PE竟然不會統計所有線程的平均延遲和總的吞吐。
隨機讀測試 RandomReadTest
在進行RandomReadTest之前,需要准備數據。准備數據建議使用SequentialWriteTest。如下面的語句
hbase pe --nomapred --oneCon=true --valueSize=100 --compress=SNAPPY --size=2 --presplit=64 sequentialWrite 64
為啥要用SequentialWriteTest?
這是因為PE寫入的行是有規律的。如果傳入的是--row=1000(代表每個線程會寫1000次),thread數是10,則寫入的行總數是1000 x 10 = 10000。在SequentialWrite中,PE會給每個線程設置偏移量,
保證0~9999這10000個行(會把所有數字擴展成26位等長的byte數組)一行不差地寫入HBase。如果是RandomWriteTest,在每個線程中會隨機生成一個0~9999之前的數字寫入。
由於是隨機,會造成中間有些行沒有寫入,那么在讀取測試時,讀到的就是空行,影響測試結果。
為啥要用--size而不是--row?
--size=2,代表寫入2GB數據,具體是多少行PE內部會自己去算。假設我這里填的是--row=1000,線程數是10,那么寫入的數據范圍是0~9999。
當我在做RandomReadTest時,如果需要修改線程數,比如我想測20個線程並行讀,那么數據讀取的范圍將是0~ (1000 * 20 - 1), 很大一部分讀是空讀!
你當然可以根據線程數來調整讀測試時row變量的值,使讀的整體范圍不超過寫入的數據范圍,但是row的大小影響了整體測試的時間,而統一用size你就啥都不用管了。
RandomReadTest的命令如下:
hbase pe --nomapred --oneCon=true --valueSize=100 --size=2 randomRead 100
注意在讀測試時不要加表的任何參數,如presplit這些,如果加了會使PE重新建表,之前寫入的數據就拜拜了。
valueSize和size的值要與准備數據命令中保持一致,PE靠這兩個值來算數據的范圍和行數。Read測試的輸出與Write測試的輸出類似。
PE工具存在的問題
PE工具雖然功能已經比較完備,但是使用下來發現還是存在一定的問題的,主要有以下幾點:
- Connection的數目設置只能由oneCon這個參數指定,要么就是一個connection,要么就是每個thread一個connection。當測試的線程數比較多時,就比較尷尬了,如果只用一個connection,connection內部的metaCache等實現都是有鎖的,在拿metacache時,線程較多會產生爭搶,影響對服務器性能的評估。如果每個thread一個connection更加不可取,每個connection中都會有一個netty的客戶端,如果我沒記錯的話,每個客戶端中將會有 2*CPU個worker threads。這在PE運行過程中產生大量的context switch,更加影響性能測試。根據我的測試發現,在開100個thread測試時,如果每個thread開一個connection,測試結果比只用一個connection的要慢10%。Context switch的頻率更是10倍以上。
- 沒有multiPut的支持,PE寫時使用的BufferedMutator需要靠調整size來決定buffer多少個put再上發。如果我想明確測試batch 5個put請求,batch10個put請求,都比較難實現。
- 沒有統計總體的RT和TPS/QPS,只有按單個thread統計,如果我用100個thread去壓服務器,這要我怎么去評估服務器的吞吐……
針對以上的問題,具體大家可以看HBASE-20601這個issue。主要的改進有:
- 加入multiPut參數,支持設置batch的數量
- 加入connCount參數,支持設置connection的多少,比如connCount=2,不管多少個thread都會共用這2個connection
- 支持統計所有線程的平均TPS,平均延遲
- 一些代碼的優化和去重
引用: