HBase——PerformanceEvaluation(压测工具)

 

简介

在项目开发过程中,我们经常需要一些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 = 20randomRead      运行随机读取测试  
 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工具虽然功能已经比较完备,但是使用下来发现还是存在一定的问题的,主要有以下几点:

  1. 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倍以上。
  2. 没有multiPut的支持,PE写时使用的BufferedMutator需要靠调整size来决定buffer多少个put再上发。如果我想明确测试batch 5个put请求,batch10个put请求,都比较难实现。
  3. 没有统计总体的RT和TPS/QPS,只有按单个thread统计,如果我用100个thread去压服务器,这要我怎么去评估服务器的吞吐……

针对以上的问题,具体大家可以看HBASE-20601这个issue。主要的改进有:

  1. 加入multiPut参数,支持设置batch的数量
  2. 加入connCount参数,支持设置connection的多少,比如connCount=2,不管多少个thread都会共用这2个connection
  3. 支持统计所有线程的平均TPS,平均延迟
  4. 一些代码的优化和去重

 

 

引用:

posted on 2020-09-09 10:01  曹伟雄  阅读(4990)  评论(0编辑  收藏  举报

导航