NoSQL性能测试工具YCSB-Running a Workload

写在前面

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

原文地址:https://github.com/brianfrankcooper/YCSB/wiki/Running-a-Workloadgit

正文

运行workload有六个步骤github

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

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

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”设置为一个属性,或者在数据库接口层中硬编码。数据库

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

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

Step 4 选择适当的运行参数

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

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

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阶段同样,因此看后续介绍

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.

相关文章
相关标签/搜索