必赢365net手机版:NoSQL品质测量检验工具YCSB,YCSB测量试验HBase远程完全布满式集群

写在前面

本文只讲一个很简单的问题,YCSB对HBase集群的测试。虽然网上有很多介绍YCSB测试HBase的文章,但都是针对本地HBase伪分布式集群的。大家都知道,稍微正式一些的压测都会要求测试客户端与目标集群分离部署,而且伪分布式集群通常不会在生产环境下使用,本身也没有太大的压测意义。本文会着重介绍一下压测远程HBase完全分布式集群的不同之处。

写在前面

目前,在系统设计中引入了越来越多的NoSQL产品,例如Redis/ MongoDB/
HBase等,其中性能指标往往会成为权衡不同NoSQL产品的关键因素。对这些产品在性能表现和产品选择上的争论,Ivan碰到不止一次。虽然通过对系统架构原理方面的分析可以大致判断出其在不同读写场景下的表现,但一是对受众有较高的要求,也来的不那么直接。这时候,没有什么比一次性能测试更有说服力。有什么好的性能测试工具呢?这就是今天的主角YCSB。YCSB是Yahoo开源的一套分布式性能测试工具,方便易用,拓展性强。Ivan最近研究HBase二级索引时用它来做性能测试,感觉还是非常顺手的。虽然网上已经有很多YCSB的介绍文章,但用来指导实际操作还是有些不便。Ivan会用两三篇文章来介绍一下YCSB的实际使用。本文是官方文章的译文,选择这篇文章是因为其与具体操作的关系比较紧密,感兴趣的同学可以了解一下。

原文地址:

正文

YCSB是Yahoo开源的性能测试工具,支持很多种类的NoSQL数据库测试,这里既包括了经典的HBase/Cassandra/MongoDB,也有近两年新推出的Spanner/Kudu等。此外,YCSB最大的特点是其灵活性,对于尚未纳入官方支持的NoSQL数据库,可以快速进行二次开发。如果你正在进行NoSQL数据库选型或者研发一款定制版Nosql数据库,那么YCSB一定是你居家旅行必备良药。

二次开发工作主要是com.yahoo.ycsb.DB的基础上定义自己的接口实现。DB是一个抽象类,定义了NoSQL数据库的5类典型操作,包括insert/update/delete/read/scan。你需要为自己的Nosql实现该上述方法。当然还有一些初始化(init)和收尾工作(cleanup)也要有相应的处理。

HBase是YCSB较早支持的NoSQL数据库,目前在主线版本上支持0.98/1.0/1.2/1.4/2.0几个版本(后两个版本是在2018-03-23增加的)。这些版本的主要差别在于对DB类的不同实现,阅读源码可以发现,在1.0版本后,DB的实现类并没有发生变化,1.2/1.4/2.0三个版本都是直接继承了1.0版,没有重载任何方法。从这点上来说,Ivan认为使用其中哪个版本测试应该都是OK的。

使用YCSB进行HBase完全分布式集群测试,主要是以下几个步骤。

正文

运行workload有六个步骤

  1. 安装待测试的数据库系统
  2. 选择适当的DB接口层
  3. 选择适当的工作负载
  4. 选择适当的运行参数(客户端线程数量,目标吞吐等)
  5. 加载数据
  6. 执行工作负载(workload)

这些步骤描述都假定你运行一个单客户端。这可以满足中小规模集群(10台左右)的测试需要。对于更大规模的集群,你必须在不同的服务器上运行多个客户端来生成足够的负载。类似地,在某些场景下,多客户机加载数据库可能更快。多客户端并行运行的更多细节,可以查看Running
a Workload in Parallel

1、搭建HBase分布式集群

Ivan的HBase版本为1.2.6,部署HBase集群具体步骤略去。

Setp 1.安装待测试的数据库

第一步是安装你希望测试的数据库。可能是单机或者集群,依赖于你要测试的配置。
你必须create 或 set up tables/keyspaces/storage
buckkets用于存储记录。这些细节对于每个数据库都不同,依赖于希望运行的负载情况。在YCSB客户端运行前,数据表必须被创建,因为客户端自身是不会请求创建数据库表的。这是因为对于某些系统创建表一个手工操作,而对于其他系统,表必须在集群启动前被创建。
workload所依赖的table必须被创建。对于核心负载,YCSB客户端将假定存在一个名为’usertable’的table,且具有灵活的schema:运行时可以根据需要增加列。’usertable’可以被映射为适当的存储容器。例如,在MySQL中,你可以create
table,在Cassandra你可以在配置中定义keyspace。数据库接口层(Step
2描述)会收到读写usertable的请求,将其转换为你所指定的实际存储的请求。这意味着你必须提供数据库接口层帮助它理解下层存储的结构。例如,在Cassandra中,你必须定义在keyspace中定义列族column
families。这样,必须创建一个列族并命名(例如,你可以使用values)。然后,数据库访问层需要理解指向values列族,或者将字符串“values”设置为一个属性,或者在数据库接口层中硬编码。

2、下载YCSB版本

Ivan选择的是YCSB0.13版本,如果使用master应该也是OK的,前文已经说过,这两个版本中HBase的访问接口是一样的。

wget https://github.com/brianfrankcooper/YCSB/archive/0.13.0-staging.zip

Step 2. 选择适当的数据库接口层

数据库接口层是一个可执行的java类,实现read、write、update、delete和scan调用,它由YCSB客户端生成,调用你的数据库API。这个类是com.yahoo.ycsb包下抽象类DB的子类。在运行YCSB客户端时,你要通过命令行指定类名,客户端会动态加载你的接口类。命令行中指定的任何属性或指定的参数文件,将会传递给数据库接口层实例,用于配置该层(例如,告诉它你要测试的数据库主机名hostname)

YCSB客户端自带一个简单的虚拟接口层,com.yahoo.ycsb.BasicDB。这层会把执行的操作通过System.out打印。这可以用于确认客户端在正常运行,用于debug
你的workload。

如何使用YCSB客户端的细节可以查看 Using the Database
Libraries。更多实现数据库接口层的细节,可以查看 Adding a Database

你可以使用YCSB命令,直接运行数据库命令。客户端使用DB接口层发送命令给数据库。你可以使用客户端确定DB层运行正常,你的数据库正确安装,DB层可以连接到数据库等等。它为大量的数据库提供了命令行接口,可以用于检验数据库的数据。运行命令行:

$ ./bin/ycsb shell basic
help
Commands:
  read key [field1 field2 ...] - Read a record
  scan key recordcount [field1 field2 ...] - Scan starting at key
  insert key name1=value1 [name2=value2 ...] - Insert a new record
  update key name1=value1 [name2=value2 ...] - Update a record
  delete key - Delete a record
  table [tablename] - Get or [set] the name of the table
  quit - Quit
3、编译YCSB

执行进行编译。

mvn clean package

由于YCSB支持了很多NoSQL数据库,所以在编译时依赖的Jar包也比较多。Ivan尝试了几次编译,都由于下载依赖包超时失败,尤其是在cassandra部分。看了下maven的输出信息,超时的部分都是测试相关的。所以调整命令如下

mvn clean package -Dmaven.test.skip=true

编译顺利完成。

Step 3 选择适当的工作负载

工作负载定义了在loading阶段将被加载进数据库的数据,在transaction阶段在数据集上执行的操作。
典型的工作负载包括以下内容:

  • Workload java class(com.yahoo.ycsb.Workload的子类)

  • Parameter file(Java Properties格式)

因为数据集的参数属性必须在两个阶段被获得,在loading阶段用于构造和插入适当类型的记录,在transaction阶段用于指定正确的记录id和field,所以参数文件在两个阶段都会使用。workload
java class使用这些属性插入记录(loading
phase)或操作那些记录(transaction
phase)。选择哪个阶段要看你运行YCSB命令行时指定的参数。

在运行YCSB客户端的命令行时,你可以指定java
class和参数文件。客户端将动态加载你的workload
class,从参数文件解析参数(和任何命令行的附加参数)并执行workload。在loading和transaction两个阶段,需要同样的属性和workload逻辑应用。例如,如果loading阶段创建10个field的记录,而后在transaction阶段必须知道有10个field可以被查询和修改。

YCSB自带的CoreWorkload
是标准workload包可以直接使用。CoreWorkload定义了简单的read/insert/update/scan操作组合。在参数文件中定义了每种操作的相应频率,以及其他workload属性。这样,修改参数文件可以执行不同的workload。更多CoreWorkload的细节,可以查看Core
Workloads

如果CoreWorkload不能满足你的需求,你可以基于com.yahoo.ycsb.Workload定义自己的workload子类。细节可以查看
Implementing New Workloads

4、添加HBase配置

本文的重点来了!!!很多人容易犯晕的地方。

事实上,如果YCSB与HBase伪分布式集群合并部署时,这部分的配置是可以忽略的。YCSB通过上下文全局变量可以直接得到HBase的信息,实现压测。可能这就是网上很多文章并不去介绍配置的原因。

我们还是从YCSB官方文档找答案,在0.94/0.98/1.0三个版本中给出的配置方式完全不同,仔细阅读发现1.0版本实际上是特别针对Google
BigTable的配置文件。这由于BigTable提供了对HBase的兼容API,YCSB将其作为一种NoSQL云服务也纳入了进来。但是此处的配置没有参考意义。在1.2版本中,虽然接口代码继承自1.0版本,但readme中明确提到配置文件要参考0.98版本,后续1.4/2.0的readme基本是照抄。

阅读0.98版本的readme,发现其实设置非常简单,我们只需要将HBase集群master节点下的hbase-site.xml文件拷贝到YCSB节点的某个位置,并在稍后的命令中指定即可。
网上有的文章会提到其他配置甚至脚步文件,这里Ivan明确的说,只需要hbase-site.xml,不需要其他文件!!!

Ivan的hbase-site.xml文件内容如下。

<configuration>
<property>
<name>hbase.rootdir</name>
<value>hdfs://master:9000/hbase</value>
</property>
<property>
<name>hbase.zookeeper.quorum</name>
<value>master,slave1,slave2</value>
</property>
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>
<property>
<name>hbase.zookeeper.property.dataDir</name>
<value>/usr/bigdata/zookeeper-3.4.11/zkData</value>
</property>
</configuration>

事实上,YCSB主要是从中读取zookeeper的节点信息。

Ivan将hbase-site.xml拷贝到/home/ycsb-hbase/conf(也可根据你的环境定义其他路径)目录下

所以相应的,请修改YCSB本地的hosts文件,将机器名与IP的对应关系维护进去。

Step 4 选择适当的运行参数

虽然workload
class和参数文件定义了具体的workload,还有一些在运行特定测试时,你可能希望指定附加的设置。这些设置可以通过YCSB客户端命令行实现。设置包括

  • -threads:
    客户端线程数量。默认,YCSB客户端使用一个worker线程,但可以指定。这通常用来根据数据库增加负载数量。
  • -target:每秒操作目标数量。默认,YCSB客户端会尝试尽可能多的操作。例如,每个操作平均花费100ms,客户端将在每个线程中每秒执行10个操作。然而,你可以限流每秒操作的数量。例如,产生一个延迟与吞吐量的曲线,你可以尝试不同的目标吞吐量,衡量每次产生的延迟。
  • -s :status.
    对于一个长时间运行的workload,它是有用的,可以获得客户端状态报告,判断他是否崩溃并给你一些过程中的信息。通过命令行指定”-s”,客户端可以每10秒报告状态到stderr。
5、创建目标表

创建usertable表,这个是YCSB测试的前置条件,测试脚本中不会自动创建

create 'usertable','family'

Step 5. 加载数据

Workload有两个执行阶段:loading阶段(定义待插入的数据)和transaction阶段(定义数据集上的操作)。为了加载数据,你要运行YCSB客户端并告诉它执行loading阶段。
例如,考虑workload A的benchmark(更多标准workloads细节在Core
Workloads)。加载标准数据集

$ ./bin/ycsb load basic -P workloads/workloada

这个命令的关注点

  • load 参数告诉客户端执行loading 阶段

  • basic
    参数告诉客户端使用BasicDB层。你可以在参数文件中指定这个属性,使用’db’属性(例如db=com.yahoo.ycsb.BasicDB)
    -P参数用来加载property文件。这个例子中,我们用来加载workload参数文件。

    加载HBase数据集:

$ ./bin/ycsb load hbase -P workloads/workloada -p columnfamily=family

这个命令的关注点

  • load 参数是告诉Client执行loading阶段操作。
  • hbase 参数是告诉Client使用HBase layer
  • -P 参数是用来加载参数文件,例子中我们用来加载workload参数文件
  • -p
    参数用于设置参数,在这个HBase例子中,我们用来设置数据库的列。你数据库中存在usertable带有family列,以执行这个命令。而后所有数据被加载到数据库
    usertable 带有family列。
  • 执行命令前,确定你已经启动了 Hadoop和 HBase

如果你使用BasicDB,你将看到数据库的insert语句。如果是你用一个实际的DB接口层,记录会被加载到数据库中。

标准workload参数文件创建很小的数据库,例如,workload仅创建1000条记录。这用于调试你的安装。然而,运行一个实际的benchmark你需要创建一个更大的数据库。例如,想象你需要加载100百万记录。然后,你需要修改workload文件中默认的“recordcount”属性。有两个办法实现。

指定一个新的属性文件,包含recordcount的新值。在命令行中,如果这个文件在workload文件后被指定,它会覆盖workload的任何属性。例如创建”large.dat”文件,仅有一行内容

recordcount=100000000

然后,client执行以下内容

$ ./bin/ycsb load basic -P workloads/workloada -P large.dat

Client会加载所有的属性文件,但使用最后加载的一个文件large.dat中的recordcount值,

通过命令行指定recordcount属性的新值。在命令行指定的任何属性都会覆盖配置文件中的属性。如下执行

$ ./bin/ycsb load basic -P workloads/workloada -p recordcount=100000000

一般来说,好的实践是在新的参数文件中存储任何重要的参数,代替通过命令行指定它们。这使得你的benchmark结果可以被复现。不用必须重建你使用的命令行,你重用参数文件即可。注意,当它开始执行时,YCSB
Client会打印处他的命令行,所以如果你将Client的输出存储到一个数据文件,你可以很容易重新执行命令行。
因为一个大数据库加载需要很长时间,你可能希望1.需要Client输出状态,2.直接将输出写入数据文件。这样,你可以执行以下命令加载数据库。

$ ./bin/ycsb load basic -P workloads/workloada -P large.dat -s > load.dat

-s 参数将要求Client向stderr输出状态报告。这样命令行的输出可能是这样

$ ./bin/ycsb load basic -P workloads/workloada -P large.dat -s > load.dat
Loading workload... (might take a few minutes in some cases for large data sets)
Starting test.
0 sec: 0 operations
10 sec: 61731 operations; 6170.6317473010795 operations/sec
20 sec: 129054 operations; 6450.76477056883 operations/sec
...

这个状态输出会帮助你看到加载操作执行得多快(这样你可以估计加载的完成时间),确认load正在执行。当load完成时,Client会报告load的性能统计数据。这些统计与transaction阶段一样,所以看后续介绍

6、执行测试命令

最后一步,只需要在命令行中增加 -cp 参数指定hbase-site.xml的路径即可。
例如以下命令。

1)加载数据

bin/ycsb load hbase10 -P workloads/workloada -cp /home/ycsb-hbase/conf -p table=usertable -p columnfamily=family -threads 100

2)执行scan测试

bin/ycsb run hbase10 -P workloads/workloade -cp /home/ycsb-hbase/conf -p table=usertable -p columnfamily=family -threads 100

打完收工。

最后啰嗦一句,YCSB测试HBase完全分布式集群的主要差异在于配置文件,即hbase-site.xml和修改本地hosts文件,目的是为了连接zookeeper集群。

更多YCSB介绍与测试命令可参考前文 NoSQL性能测试工具YCSB-Running a
Workload

Step 6 执行workload

一旦数据被加载,你就可以执行workload。告诉Client执行transaction操作。执行workload,可以使用以下命令

$ ./bin/ycsb run basic -P workloads/workloada -P large.dat -s > transactions.dat

主要差别是我们使用run参数时,告诉Client执行transaction阶段而不是loading阶段。如果你使用BasicDB,检查结果文件
transactions.dat,你会看到一个read和update混合的请求,与统计数据一致。

典型情况下,你会希望使用 -threads 和 -target
参数控制负荷量。例如,你可能希望10个线程每秒总数100个操作。平均操作延时不高于100ms,每个线程能够携带每秒10此操作。一般来说,你需要足够的线程因为没有线程尝试每秒更多的操作,否则你达到的吞吐量将小于指定的目标吞吐量。
这个例子,我们可以执行

$ ./bin/ycsb run basic -P workloads/workloada -P large.dat -s -threads 10 -target 100 > transactions.dat

注意这个例子,我们使用 -threads 10 命令参数指定10个线程, -target 100
命令参数指定每秒100次操作。否则,两个值可以设置在你的参数文件中,使用threadcount
和 target 属性代替。例如

threadcount=10
target=100

run的结尾,Client会向stdout报告性能统计数据。上面的例子,统计数据会写入transaction.dat文件。默认包括每个操作类型延时的average,min,max,95th,99th。每次操作返回代码的统计,每类操作的直方图。返回值被你的DB接口层定义,允许你看到workload过程中的任何错误。上述例子中,我们可以得到输出:

[OVERALL],RunTime(ms), 10110
[OVERALL],Throughput(ops/sec), 98.91196834817013
[UPDATE], Operations, 491
[UPDATE], AverageLatency(ms), 0.054989816700611
[UPDATE], MinLatency(ms), 0
[UPDATE], MaxLatency(ms), 1
[UPDATE], 95thPercentileLatency(ms), 1
[UPDATE], 99thPercentileLatency(ms), 1
[UPDATE], Return=0, 491
[UPDATE], 0, 464
[UPDATE], 1, 27
[UPDATE], 2, 0
[UPDATE], 3, 0
[UPDATE], 4, 0
...

这个输出指标

  • 总体执行时间为10.11秒

  • 平均吞吐量98.9 ops(所有线程)

  • 491次修改操作,附带average,min,max,95th,99th %延迟情况
  • 所有491次修改操作都返回0(成功)
  • 464次操作在1ms内完成,27次在1至2ms内完成。

读操作有与之接近的统计数值

延时信息的直方图通常是有用的,时序图的形式有时更有用。请求一个时序,需要在Client命令行或在属性文件指定”measureenttype=timeseries”属性。默认情况下,Client会每间隔1000ms,报告一次平均延时。你可以对报告指定不同的间隔粒度,使用
timeseries.granularity属性,例如。

$ ./bin/ycsb run basic -P workloads/workloada -P large.dat -s -threads 10 -target 100 -p measurementtype=timeseries -p timeseries.granularity=2000 > transactions.dat

将会报告一个时序,间隔2000ms读一次,结果将是。

[OVERALL],RunTime(ms), 10077
[OVERALL],Throughput(ops/sec), 9923.58836955443
[UPDATE], Operations, 50396
[UPDATE], AverageLatency(ms), 0.04339630129375347
[UPDATE], MinLatency(ms), 0
[UPDATE], MaxLatency(ms), 338
[UPDATE], Return=0, 50396
[UPDATE], 0, 0.10264765784114054
[UPDATE], 2000, 0.026989343690867442
[UPDATE], 4000, 0.0352882703777336
[UPDATE], 6000, 0.004238958990536277
[UPDATE], 8000, 0.052813085033008175
[UPDATE], 10000, 0.0
[READ], Operations, 49604
[READ], AverageLatency(ms), 0.038242883638416256
[READ], MinLatency(ms), 0
[READ], MaxLatency(ms), 230
[READ], Return=0, 49604
[READ], 0, 0.08997245741099663
[READ], 2000, 0.02207505518763797
[READ], 4000, 0.03188493260913297
[READ], 6000, 0.004869141813755326
[READ], 8000, 0.04355329949238579
[READ], 10000, 0.005405405405405406

这个输出分开显示了update和read操作的时间序列,每2000ms的数据。数据报告的时点是仅包括前一个2000ms的均值。(这个例子,我们做了100,000次操作,目标是每秒10,000次操作)。一个关于延时度量的关注点:Client度量,特定操作对数据库的端到端的执行延时。那样,它在调用DB接口层class适当方法前会启动启动一个时钟,方法返回时会停止时钟。延时包括:执行包括接口层,到数据库服务器的网络延迟,数据库的执行时间。不包括用于控制吞吐量的延迟。就是说,如果你指定目标是每秒10次操作(单线程)Client会在每100ms仅执行1次操作。如果操作耗费了12ms,Client会在下一次操作前额外等待88ms。然而,报告延时不会包括这个等待时间,报告会显示延迟是12ms而不是100.

Leave a Comment.