YCSB-README翻译

概览
当前YCSB支持很多数据库包括:
HBase
Hypertable
Cassandra
Couchbase
Voldemort
MongoDB
OrientDB
Infinispan
Redis
GemFire
DynamoDB
Tarantool
Memcached
…and many others
很难决定那个系统适合你的应用,部分因为系统间的特性不同,部分因为没有简单的方法来比较两个系统间的性能。

YCSB项目的目标是,发展一个框架和通用数据集用来评估不同键值存储和云存储的性能。项目包括两部分:

YCSB客户端,一个扩展的负载生成器
核心负载,一系列负载场景用于生成器来执行。

尽管核心负载提供了提供性能的一个大致图景,客户端也是可扩展的,你可以定义新的不同的负载来检验系统没有被核心负载覆盖的方面。类似,客户端也可以扩展来支持测试不同的数据库。尽管我们包含了测试hbase,cassandra,infinispan,mongodb等的样例代码,写一个新的接口层来测试你最喜欢的数据库也是很直接的。

这个工具的通用功能是测试多个系统并比较他们。例如,你可以在同样配置下安装多个系统,并分别运行相同负载。那么你就可以画出每个系统的性能来观察什么时候一个系统超过另一个。

Next

  1. Getting Started
  2. Running a Workload
  3. Adding a Database

1.获取YCSB
git clone git://github.com/brianfrankcooper/YCSB.git
cd YCSB
mvn clean package
./bin/ycsb

2.运行负载
运行负载有6步操作:
设置要测试的数据库系统
选择合适的DB接口层
选择合适的负载
选择合适的运行时参数(客户端线程数量,target吞吐率)
加载数据
执行负载

这里描述的步骤假设,你运行一个单机的客户端服务器。这对于小型和中型的集群都足够了(10台机器左右)。对于大得多的集群,你可能会在不同服务器上运行不同client来生成足够的负载。类似,加载数据库在使用更多client机器时可能会更快。了解更多关于并行在多个client上运行的细节,看Running a Workload in Parallel.

第一步,设置测试的数据库系统
这可以在一台机器或是集群上完成,取决于你想要测试的配置。

你必须创建或设置tables/keyspaces/storage 桶来存储记录。具体细节根据不同数据库系统有所变化,依赖于你想要运行的负载。在YCSB客户端运行之前,tables必须被创建,因为client本身不会请求创建tables。这是因为对一些系统来说,有手工步骤来创建tables,对其他系统,table必须在书库集群开始之前被创建好。

必须被创建的table依赖于负载。对于核心负载,YCSB客户端会将设有一个table叫做usertable,有一个灵活的结构:列能在运行时添加。这个usertable能被映射到存储容器合适的任何结构。例如,在MYSQL中,是CREATE TABLE;在cassandra,定义一个keyspace等等。数据库接口层(第二步)将接受在usertable中读写记录的请求,并将他们转换成对你分配的实际存储的请求。这可能意味着你不得不给数据库接口层提供信息来帮助它理解底层存储的结构是什么。例如,在cassandra,你必须在keyspace之外定义列族的概念。这样,创建列族并给它一个名字就很必要(values)。然后,数据库访问层将需要了解引用values列族,或者因为values被作为属性传输,或因为它被硬编码进了数据库接口层。

第二步,选择合适的DB接口层
DB接口层是一个执行YCSB客户端生成的read,insert,update,delete,scan的java 类,转换成对自定义数据库API的调用。这个类是com.yahoo.ycsb包的一抽象DB类的子类。你必须在命令行中运行YCSB客户端时制定接口层的类的名字,然后client将动态加载你的接口类。任何在命令行中指定的属性,或在命令行中指定的属性文件,将被传给DB接口实例,从而被用来配置接口层(例如,传输你在测试的数据库的主机地址)。

YCSB客户端和一个简单的不起作用的接口层com.yahoo.ycsb.BasicDB放在一起。这层仅仅打印执行的操作到system.out。它用来保证客户端正确的执行,并用来debug负载。

看 Using the Database Libraries了解如何在运行YCSB时使用client的细节。关于如何实现一个DB接口层,看Adding a Database.

你可以使用ycsb命令直接在数据库上运行命令。这个client使用DB接口层来发送命令给数据库。你可以用这个client来保证DB接口层工作正常,数据库设置正确,DB层能连接到数据库等等。它也为各种数据库提供一个通用接口,也能被用来查看数据库中的数据。运行命令行client的方法:

$ ./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

第三步,选择合适的负载
负载定义了将在load阶段加载到数据库中的数据,和在transaction阶段被执行的操作。

通常来说,负载是以下的集合:

负载java类(com.yahoo.ycsb.Workload子类)
参数文件(以java属性格式)
因为数据集的属性在load阶段必须被了解(才能构建合适种类的记录并插入他们),以及在transaction阶段(才能让正确的记录id和field被引用),一个单独的属性集合在两个阶段被共享。这样,参数文件在两个阶段被使用。负载java类使用那些属性,或者添加记录(load阶段)或者执行transaction提交记录(transaction阶段)。选择执行那个阶段,基于当你运行ycsb命令时指定的一个参数。

当你在运行YCSB客户端是,在命令行中指定jajva类和参数文件。client将动态的加载你的负载类,从参数文件中提取属性(和任何其他命令行中指定的属性),然后执行负载。这在load和transaction阶段发生,同样的属性和负载逻辑应用在两个阶段。例如,如果敷在阶段创建了有10个字段的记录,那么transaction阶段必须知道有10个字段它可以访问和修改。

核心负载是与YCSB放在一起的标准负载包,能被直接使用。尤其是,核心负载定义了简单的read、insert、update、scan操作的混合。每个操作的相对频率在参数文件中定义,就像负载的其他参数。这样,通过改变参数文件,各种不同的离散负载可以被执行。想了解更多核心负载的细节,查看 Core Workloads.

如果核心负载没有满足你的需求,你可以定义自己的负载通过集成com.yahoo.ycsb.Workload类。细节在Implementing New Workloads.

第四步:选择合适的运行时参数
尽管负载类和参数文件定义了一个特定的负载,还有其他一些设置你可以在运行测试时指定。这些设置在你运行YCSB客户端时指定,包括:

-threads :
客户端线程的数量,默认的,YCSB使用一个工作线程,但是额外的线程可以被指定。这通常被用来增加数据库的load数量。
-target :
每秒的预期操作数。默认,YCSB将执行尽可能多的操作。例如,如果每个操作平均花费100毫秒,client将每个工作线程每秒执行10个操作。然而,你可以对每秒执行的操作数量进行限流。例如,为了生成延迟-吞吐率曲线,你可以尝试不同的预期吞吐率,并测量每个的实际延迟。
-s :
状态,对一个长期运行的负载,让client报告状态是有意义的,可以保证它没有崩溃并且给你一些测试进程的反馈。通过在命令行制定 -s,client将每秒向stderr报告状态。

第五步,加载数据
负载有两个执行阶段:加载(定义了插入的数据),事务阶段(定义了在数据集上执行的操作)。为了加载数据,你要运行YCSB client并告诉他执行load阶段。

例如,考虑测试负载A(更多细节查看Core Workloads),为了加载标准数据集:

$ ./bin/ycsb load basic -P workloads/workloada
几点标注:

The “-P” parameter is used to load property files. In this case, we used it to load the workloada parameter file.
To load the HBase dataset:
load参数告诉client执行负载的load阶段。
basic参数桃酥client使用不起作用的basicDB接口层。你也能在你的参数文件中使用db属性指定(例如"db=com.yahoo.ycsb.BasicDB")

$ ./bin/ycsb load hbase -P workloads/workloada -p columnfamily=family
几点标注:

load参数告诉client执行负载加载阶段。
hbase参数告诉client使用HBase接口层。
-P参数被用来加载属性文件。在这里,我们使用它来加载workloada参数文件。
-p参数用来设置参数。在这个hbase例子中,我们用它来设置数据库列。你应该在运行这个命令有一个带有列族的数据库usertable。那么所有数据将被加载到带有列族的数据库usertable中。
保证你已经启动了hadoop和hbase在运行这条命令前。
如果你用basicdb,你将看到数据库的插入statement。如果你使用一个真实的数据库接口层,记录将被插入到数据库中。

标准负载参数文件创建非常小的数据库;例如,workloada创建1000条记录。这在debug你的setup时非常有用。然而,在实际测试中你可能想要生成一个更大的数据库。例如,想象你想要load100 million记录,那么,你要重写workloada文件中的recordcount属性。这可以以下面两种方式之一完成。

制定一个包含新recordcount值的新属性文件。如果这个文件在命令行中在workloada后面指定,它将覆盖workloada中的属性。例如,创建一个叫做large.dat的包含如下一行的文件:

recordcount=100000000
然后,运行client如下:

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

client将load两个属性文件,但会使用最后一个文件指定的recordcount的值。

在命令行指定recordcount属性的新值。任何命令行中指定的属性都会覆盖属性文件中的。例如:

$ ./bin/ycsb load basic -P workloads/workloada -p recordcount=100000000
通常,将重要的属性保存在新的参数文件是合理的,而不是在命令行中指定他们。这使你的测试结果可重复;而不是重新创建之前用过的命令行。注意,YCSB将在开始执行时打印命令行,因此如果你把client的输出保存在data文件中,你可以从文件中恢复命令行。

因为一个大的数据库负载会花很长时间,你可能想要:1.要求client输出状态2.将输出导向到datafile。这样,你可以如下执行load:

$ ./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完成的时间)并且验证load确实在进行。当load完成,client会报告load性能的参数统计。这些统计量和transaction阶段的一样,看下面了解参数的信息。

第六步:执行负载
一旦数据被加载,你可以执行负载。只要告诉client执行负载的transaction阶段。为了执行负载,你可以使用以下命令。

$ ./bin/ycsb run basic -P workloads/workloada -P large.dat -s > transactions.dat
在这个调用中的主要区别就是,我们使用run参数告诉client,执行transaction阶段而不是load阶段。如果你使用basicDB,并且检查结果的transactions.dat,就会看到read和update请求的组合,和关于执行的参数。

通常,你将使用-threads和-target参数来控制提供负载的数量。例如,我们可能想要10个线程尝试每秒一共100个操作(每个线程每秒10ops)。只要每个操作的平均延迟不高于100ms。通常,你需要足够的线程以至于没有线程需要超负荷发挥,否则的话你实际的吞吐率将低于预期吞吐率。如下:

$ ./bin/ycsb run basic -P workloads/workloada -P large.dat -s -threads 10 -target 100 > transactions.dat
注意在这个例子中,我们用命令行参数-threads 10,-target 100来指定。同样,两个值也都可以在参数文件中使用threadcount和target属性来指定,例如:

threadcount=10
target=100
在运行最后,client会在stdout报告性能参数。在上面的例子中,这些参数被写到transactions.dat文件。默认包括每个操作类型(read,update)average,min,max,95th和99th延迟和每个操作延迟的柱状图。返回的代码是由数据库接口层定义,并且允许你观察在负载其间是否有错误发生。对上面的例子,我们可能得到如下输出:

[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

This output indicates:

The total execution time was 10.11 seconds
The average throughput was 98.9 operations/sec (across all threads)
There were 491 update operations, with associated average, min, max, 95th and 99th percentile latencies
All 491 update operations had a return code of zero (success in this case)
464 operations completed in less than 1 ms, while 27 completed between 1 and 2 ms.
Similar statistics are available for the read operations.

延迟的柱状图通常很有用,有时时间序列更有用。为了得到时间序列,指定"measurementtype=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
will report a timeseries, with readings averaged every 2,000 milliseconds (e.g. 2 seconds). The result will be:

[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的平均值。(在这个例子中,我们使用100K个操作和每秒10K的target得到一个有趣的结果)关于延迟测量的一个标注:client测量在数据库上执行特定操作的结束延迟。意味着,client在DB接口层调用对应方法前开启定时器,在方法返回时结束定时器。这样,延迟包括:在接口层内部执行,到数据库服务器的网络延迟,数据库施行时间三部分。不包括对target吞吐率的限流延迟。即,如果你指定target每秒10op(一个单独线程),那么client将每100ms只执行一个op。如果op花费了12ms,那么client会在尝试下次op之前等待88ms。然而,报告的延迟不会包括这88ms,延迟只有12ms,而不是100.

3.添加数据库

实现一个数据库接口层 概览
数据库接口层向YCSBclient隐藏你测试的数据库的具体细节。这使得client可以不用理解你数据库的API就能生成像读取记录,更新记录这样的op。这样,就很容易测试新的数据库系统。一旦你创建了数据库接口层,测试框架的其他部分不用改变就能运行。

数据库接口层是一个简单的抽象类,它提供read,insert,update,delete,scan操作。实现你数据库的接口层意味着填满这些方法的实现。一旦你编译好了自己的接口层,你可以在命令行指定实现类的名字告诉YCSBclient。YCSBclient将在开始时动态加载你的实现。这样,你不需要重新编译YCSBclient来添加或改变数据库接口层。

一步一步创建一个新接口层
第一步,给你数据库创建一个模块
最好的开始方式是,熟悉一下其他数据库接口层模块诸如couchbase,mongodb,cassandra2。数据库接口模块是在YCSB项目顶层的目录,通常以他们接通的数据库的名字命名。每个模块都是一个自恰的java项目。

开始为你的数据库创建一个顶层目录。包括一个pom.xml来指定你的接口包编译需要的任何依赖。README.md来描述你的接口以及如何使用,最后是一个包含你的java类的通用maven项目结构

第二步,扩展com.yahoo.ycsb.DB.
所有数据库接口层实现的父类都是com.yahoo.ycsb.DB。这是一个抽象类,因此你需要创建一个新类来继承它。你的类必须有一个public的无参构造器,因为在工厂里实例会通过无参构造器来创建。

YCSB客户端框架将在每个工作者线程创建一个DB类的实例,但可能有多个工作者线程生成负载,因此可能有多个你的DB类实例被创建。

第三步,如果必要实现init()函数
你可以通过实现下面的方法来执行DB对象的初始化。

public void init() throws DBException

init()方法应该被用来设置到数据库的链接和做任何初始化操作。尤其是,你可以使用在运行时传给YCSB客户端的属性来配置数据库接口层。事实上,YCSB客户端将把CLIENT启动时参数文件中指定的所有属性都传给DB接口层。这样,你可以创建配置DB接口层的新的属性,在参数文件或命令行设置他们,然后在你的DB接口层中恢复他们。

这些属性将在构造函数之后传给DB实例,因此在init()而不是构造器中恢复他们是很重要。你可以用下面的函数恢复他们。

public Properties getProperties()
该方法已经实现在DB基类中。

第四步,实现数据库查询和更新方法
你需要实现的方法有:

//Read a single record
public int read(String table, String key, Set fields, HashMap<String,String> result);

//Perform a range scan
public int scan(String table, String startkey, int recordcount, Set fields, Vector<HashMap<String,String>> result);

//Update a single record
public int update(String table, String key, HashMap<String,String> values);

//Insert a single record
public int insert(String table, String key, HashMap<String,String> values);

//Delete a single record
public int delete(String table, String key);
在每个例子中,方法接受一个table名和记录的key。(在scan的例子中,record key是最开始扫描的key)对于度方法(read,scan),方法额外需要一些属性来读取,并提供一个结构体存放返回的结构。对于写方法(insert,update),方法用hashmap映射字段名到字段值。

数据库应该在运行测试之前就创建合适的表。因此你可以在上面的方法实现中假设,对应的表已经存在,并且直接写从table参数对应的表中读取和写入的方法。

第五步,编译你的数据库接口层

你的代码可以和YCSB客户端和框架分开编译。尤其是,在修改并重新编译你的DB类时,不用顾忌YCSB客户端。

第六步,测试数据库接口层
简单的测试方法是使用YCSB包含的命令行客户端。这个客户端创建一个DB实例,并允许你不用开启一个负载就直接和数据库交互。例如,使用命令行和MONGODB交互:

% java com.yahoo.ycsb.CommandLine -db com.yahoo.ycsb.db.MongoDbClient -p mongodb.url=mongodb://localhost:27017 -p mongodb.database=ycsb
YCSB Command Line client
Type “help” for command line help
Start with “-help” for usage info
Connected.

insert brianfrankcooper first=brian last=cooper
Return code: 1
191 ms
read brianfrankcooper
Return code: 0
last=cooper
_id=brianfrankcooper
first=brian
2 ms
quit

第七步,与YCSB客户端一起使用
确保你的类的实现是在CLASSPATH中可用的,以及任何你的视线中使用的libraries/jar文件。现在,当你运行YCSB客户端时,在命令行指定-db参数并提供你的DB类的完整名字,例如,

% java -cp build/ycsb.jar:yourjarpath com.yahoo.ycsb.Client -t -db com.foo.YourDBClass -P workloads/workloada -P large.dat -s > transactions.dat
你也可以在参数文件中使用DB属性来指定DB接口类
db=com.foo.YourDBClass

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值