HBase基准性能测试报告


本次测试主要评估线上HBase的整体性能,量化当前HBase的性能指标,对各种场景下HBase性能表现进行评估,为业务应用提供参考。本篇文章主要介绍此次测试的基本条件,HBase在各种测试场景下的性能指标(主要包括单次请求平均延迟和系统吞吐量)以及对应的资源利用情况,并对各种测试结果进行分析。

测试环境

测试环境包括测试过程中HBase集群的拓扑结构、以及需要用到的硬件和软件资源,硬件资源包括:测试机器配置、网络状态等等,软件资源包括操作系统、HBase相关软件以及测试工具等。

集群拓扑结构

本次测试中,测试环境总共包含4台SA5212H2物理机作为数据存储。生成数据的YCSB程序与数据库并不运行在相同的物理集群。

单台机器主机硬件配置

软件版本信息

测试工具

YCSB全称Yahoo! Cloud Serving Benchmark,是Yahoo公司开发的专门用于NoSQL测试的基准测试工具。github地址:https://github.com/brianfrankcooper/YCSB YCSB支持各种不同的数据分布方式

1. Uniform:等概论随机选择记录 

2. Zipfian:随机选择记录,存在热记录 

3. Latest:近期写入的记录为热记录

测试场景

YCSB为HBase提供了多种场景下的测试,本次测试中,我们导入10亿条数据,并对如下场景进行测试:

YCSB并没有提供Increment相关的测试功能,但是部分业务有这方面的需求,因此对YCBS进行了改造,加入了Increment模块。需要注意的是,在测试Increment性能前需要导入1亿条数字进行测试。写入和查询的数据模拟目前线上记录的长度,具有以下特性:

HBase相关重要配置

hfile.block.cache.size:0.2
hbase.regionserver.global.memstore.upperLimit:0.45
jvm:-Xms48g -Xmx48g -Xmn4g -Xss256k -XX:PermSize=256m -XX:MaxPermSize=256m

jvm参数表示每台机器会分配48G内存作为Java的堆内存使用,hfile.block.cache.size参数表示HBase会为每台Region Server分配大小为9.6G(48 * 0.2)的内存作为读缓存使用。hbase.regionserver.global.memstore.upperLimit参数表示HBase会为每台Region Server最多分配大小为21.6G(48 * 0.45)的内存作为写缓存使用。

测试方法

上述测试场景中部分测试(插入测试、scan扫描查询等)对客户端带宽资源要求很高,单个客户端测试会因为客户端带宽耗尽而导致无法测出实际服务器集群读写性能,因此我们开启6个YCBS客户端并发进行测试,最终Throughput是6个客户端的总和,AverageLatency取6个客户端延迟的平均值。

单个YCSB测试都遵守标准测试流程,基本流程如下:

1. 在6个客户端服务器部署YCSB程序,向集群中load 10亿条数据

2. 按照预先定义的场景修改负载文件workload

3. 使用ycsb run方法执行测试,向集群写入读取数据

4. 进行数据操作时通过YCSB记录产生的统计数据,主要是吞吐量和平均延迟两个指标

5. 根据结果生成对应的图标

6. 针对不同场景,重复上述测试步骤


测试结果

单条记录插入

测试参数

总记录数为10亿,分为128region,均匀分布在4region server上;插入操作执行2千万次;插入请求分布遵从zipfian分布;

测试结果

资源使用情况

上图为单台RegionServer的带宽使用曲线图(资源使用情况中只列出和本次测试相关的资源曲线图,后面相关资源使用情况类似),本次测试线程为1000的情况下带宽基本维持在100M左右,对于百兆网卡来说基本上已经打满。

结果分析

1.     吞吐量曲线分析:线程数在10~500的情况下,随着线程数的增加,系统吞吐量会不断升高;之后线程数再增加,系统吞吐量基本上不再变化。结合图3带宽资源使用曲线图可以看出,当线程数增加到一定程度,系统带宽资源基本耗尽,系统吞吐量就不再会增加。可见,HBase写操作是一个带宽敏感型操作,当带宽资源bound后,写入吞吐量基本就会稳定。

2.     写入延迟曲线分析:随着线程数的不断增加,写入延迟也会不断增大。这是因为写入线程过多,导致CPU资源调度频繁,单个线程分配到的CPU资源会不断降低;另一方面由于线程之间可能会存在互斥操作导致线程阻塞;这些因素都会导致写入延迟不断增大。

建议

根据曲线显示,500线程以内的写入延迟并不大于10ms,而此时吞吐量基本最大,因此如果是单纯写入的话500线程写入会是一个比较合适的选择。


单纯查询

测试参数


总记录数为10亿,分为128region,均匀分布在4region server上;查询操作执行2千万次;查询请求分布遵从zipfian分布;

测试结果

资源使用情况

5为线程数在1000IO利用率曲线图,图中IO利用率基本保持在100%,说明IO资源已经达到使用上限。图6为线程数在1000时系统负载曲线图,图中load1曲线表示在最近一分钟内的平均负载,load5表示最近五分钟内的平均负载。最近5分钟的负责达到了50左右,对于32核系统来说,表示此时系统负载很高,已经远远超负荷运行。

结果分析

1.     吞吐量曲线分析:线程数在10~500的情况下,随着线程数的增加,系统吞吐量会不断升高;之后线程数再增加,系统吞吐量基本上不再变化。结合图5、图6系统资源使用曲线图可以看出,当线程数增加到一定程度,系统IO资源基本达到上限,系统负载也特别高。IO利用率达到100%是因为大量的读操作都需要从磁盘查找数据,系统负载很高是因为HBase需要对查找的数据进行解压缩操作,解压缩操作需要耗费大量CPU资源。这两个因素结合导致系统吞吐量就不再随着线程数增肌而增加。可见,HBase读操作是一个IO/CPU敏感型操作,当IO或者CPU资源bound后,读取吞吐量基本就会稳定不变。

2.     延迟曲线分析:随着线程数的不断增加,读取延迟也会不断增大。这是因为读取线程过多,导致CPU资源调度频繁,单个线程分配到的CPU资源会不断降低;另一方面由于线程之间可能会存在互斥操作导致线程阻塞;这些因素都会导致写入延迟不断增大。和写入延迟相比,读取延迟会更大,是因为读取涉及IO操作,IO本身就是一个耗时操作,导致延迟更高。

建议

根据曲线显示,500线程以内的读取延迟并不大于20ms,而此时吞吐量基本最大,因此如果是单纯读取的话500线程读取会是一个比较合适的选择。

Range扫描查询

测试参数

总记录数为10亿,分为128region,均匀分布在4region server上;scan操作执行一千两百万次,请求分布遵从zipfian分布; scan最大长度为100条记录, scan长度随机分布且遵从uniform分布;

测试结果

资源使用情况

8为线程数在1000IO利用率曲线图,图中IO利用率基本保持在100%,说明IO资源已经达到使用上限。图9为线程数在1000时带宽资源使用曲线图,图中带宽资源基本也已经达到上限。

结果分析

1.     吞吐量曲线分析:线程数在10~500的情况下,随着线程数的增加,系统吞吐量会不断升高;之后线程数再增加,系统吞吐量基本上不再变化。结合图8 、图9资源使用曲线图可以看出,当线程数增加到一定程度,系统IO资源基本达到上限,带宽也基本达到上限。IO利用率达到100%是因为大量的读操作都需要从磁盘查找数据,而带宽负载很高是因为每次scan操作最多可以获取50Kbyte数据,TPS太高会导致数据量很大,因而带宽负载很高。两者结合导致系统吞吐量就不再随着线程数增大会增大。可见,scan操作是一个IO/带宽敏感型操作,当IO或者带宽资源bound后,scan吞吐量基本就会稳定不变。

2.     延迟曲线分析:随着线程数的不断增加,读取延迟也会不断增大。这是因为读取线程过多,导致CPU资源调度频繁,单个线程分配到的CPU资源会不断降低;另一方面由于线程之间可能会存在互斥操作导致线程阻塞;这些因素都会导致写入延迟不断增大。和写入延迟以及单次随机查找相比,读取延迟会更大,是因为scan操作会涉及多次IO操作,IO本身就是一个耗时操作,因此会导致延迟更高。

建议

根据图表显示,用户可以根据业务实际情况选择100~500之间的线程数来执行scan操作。


查询插入平衡

测试参数


总记录数为10亿,分为128region,均匀分布在4region server上;查询插入操作共执行8千万次;查询请求分布遵从zipfian分布;

测试结果

资源使用情况

11为线程数在1000时系统IO利用率曲线图,图中IO利用率基本保持在100%,说明IO资源已经达到使用上限。图12为线程数在1000时系统负载曲线图,图中显示CPU负载资源达到了40+,对于只有32核的系统来说,已经远远超负荷工作了。

结果分析

1.    吞吐量曲线分析:线程数在10~500的情况下,随着线程数的增加,系统吞吐量会不断升高;之后线程数再增加,系统吞吐量变化就比较缓慢。结合图11、图12系统资源使用曲线图可以看出,当线程数增加到一定程度,系统IO资源基本达到上限,带宽也基本达到上限。IO利用率达到100%是因为大量的读操作都需要从磁盘查找数据,而系统负载很高是因为大量读取操作需要进行解压缩操作,而且线程数很大本身就需要更多CPU资源。因此导致系统吞吐量就不再会增加。可见,查询插入平衡场景下,当IO或者CPU资源bound后,系统吞吐量基本就会稳定不变。

2.     延迟曲线分析:随着线程数的不断增加,读取延迟也会不断增大。这是因为读取线程过多,导致CPU资源调度频繁,单个线程分配到的CPU资源会不断降低;另一方面由于线程之间可能会存在互斥操作导致线程阻塞;这些因素都会导致写入延迟不断增大。图中读延迟大于写延迟是因为读取操作涉及到IO操作,比较耗时。

建议

根据图表显示,在查询插入平衡场景下用户可以根据业务实际情况选择100~500之间的线程数。


插入为主

测试参数

总记录数为10亿,分为128region,均匀分布在4region server上;查询插入操作共执行4千万次;查询请求分布遵从latest分布;

测试结果

资源使用情况


15为线程数在1000时系统带宽使用曲线图,图中系统带宽资源基本到达上限,而总体IO利用率还比较低。

结果分析

1.    曲线分析:线程数在10~500的情况下,随着线程数的增加,系统吞吐量会不断升高;之后线程数再增加,系统吞吐量基本上不再变化。结合图14带宽资源使用曲线图可以看出,当线程数增加到一定程度,系统带宽资源基本耗尽,系统吞吐量就不再会增加。基本同单条记录插入场景相同。

2.    写入延迟曲线分析: 基本同单条记录插入场景。

建议

根据图表显示,插入为主的场景下用户可以根据业务实际情况选择500左右的线程数来执行。


查询为主

测试参数


总记录数为10亿,分为128region,均匀分布在4region server上;查询插入操作共执行4千万次;查询请求分布遵从zipfian分布;

测试结果

资源使用情况

17为线程数在1000IO利用率曲线图,图中IO利用率基本保持在100%,说明IO资源已经达到使用上限。

结果分析

基本分析见单纯查询一节,原理类似。

建议

根据图表显示,查询为主的场景下用户可以根据业务实际情况选择100~500之间的线程数来执行。

Increment自增

测试参数

1亿条数据,分成16Region,分布在4RegionServer上;操作次数为100万次;

测试结果

结果分析

1.    线程数增加,Increment操作的吞吐量会不断增加,线程数到达100个左右时,吞吐量会达到顶峰(23785 ops/sec),之后再增加线程数,吞吐量基本维持不变;

2.    随着线程数增加,Increment操作的平均延迟会不断增加。线程数在100以下,平均延时都在4ms以内;

建议

根据图表显示,查询为主的场景下用户可以根据业务实际情况选择100~500之间的线程数来执行。


测试结果总结

根据以上测试结果和资源利用情况可以得出如下几点:

1. 写性能:集群吞吐量最大可以达到70000+ ops/sec,延迟在几个毫秒左右。网络带宽是主要瓶颈,如果将千兆网卡换成万兆网卡,吞吐量还可以继续增加,甚至达到目前吞吐量的两倍。

2. 读性能:很多人对HBase的印象可能都是写性能很好、读性能很差,但实际上HBase的读性能远远超过大家的预期。集群吞吐量最大可以达到26000+,单台吞吐量可以达到8000+左右,延迟在几毫秒~20毫秒左右。IO和CPU是主要瓶颈。

3. Range 扫描性能:集群吞吐量最大可以达到14000左右,系统平均延迟在几毫秒~60毫秒之间(线程数越多,延迟越大);其中IO和网络带宽是主要瓶颈。


测试注意事项

1. 需要关注是否是全内存测试,全内存测试和非全内存测试结果相差会比较大。参考线上实际数据情况,本次测试采用非全内存读测试。是否是全内存读取决于总数据量大小、集群Jvm内存大小、Block Cache占比、访问分布是否是热点访问这四者,在JVM内存大小以及Block Cache占比不变的情况下,可以增大总数据量大小或者修改访问分布;

2. 测试客户端是否存在瓶颈。HBase测试某些场景特别耗费带宽资源,如果单个客户端进行测试很可能会因为客户端带宽被耗尽导致无法测出实际服务器集群性能。本次测试使用6个客户端并发进行测试。

3. 单条记录大小对测试的影响。单条记录设置太大,会导致并发插入操作占用大量带宽资源进而性能产生瓶颈。而设置太小,测试出来的TPS峰值会比较大,和线上实际数据不符。本次测试单条数据大小设置为50M,基本和实际情况相符。


本文来自网易实践者社区,经作者范欣欣授权发布。