NoSQLBench压测工具入门教程
NoSQLBench发布于2020年3月,它是第一个试图在分布式系统性能测试上做到面面俱到的专业测试工具。同时,它旨在让轻量级的和专业的用户都可以使用。
什么是NoSQLBench?
当今的开发人员希望创造性能可扩展的应用程序。这就要求使用在多地运行的分布式系统,无论是容器镜像或是跨公共、私有或混合云平台运行的服务。然而,测试这些应用程序往往比想象的要难。
可扩展的系统的性能测试工具一直都很有限。NoSQLBench发布于2020年3月,它是第一个试图在分布式系统上做到面面俱到的专业测试工具。同时,它旨在让轻量级的和专业的用户都可以使用。
NoSQLBench致力于解决其他工具无法解决的测试难题。它允许用户使用目标系统的原生查询语言对访问模式进行建模。它不假定所有NoSQL数据库只是同一概念的不同版本。用NoSQLBench进行实际测试并不需要您是专业的程序员,也不需要您传输巨量数据来得到真实的测试数据或操作。
使用NoSQLBench配置了一个工作负载workload后,就可以开始测试了。如果需要更改访问模式或操作中使用的数据,只需要更改配置,就可以再次测试。这个过程如此简单,即使是任意大小的数据集也可如此操作。这样用户可以直观的洞察到生产环境中同样的工作负载会是什么样的效果。
NoSQLBench具有其他测试工具不具备的功能
- 基于模版的的过程式数据生成——使用函数轻松复制和粘贴海量的虚拟数据集
- 确定性的工作负载的表现——每个周期cycle都是特定并可重复的
- 模块化协议支持——包括cql及其他
- 语句和数据的配置语言——操作和访问模式的语言
- 内置脚本——启用自动机驱动的高级场景分析
- 基于周期cycle的操作和诊断——可以重试任何特定的周期以了解更多信息
- docker-metrics监控界面——支持自动运行和配置基于docker的grafana功能栈,以实现丰富的监控界面
- 协调一致的显示高保真的性能指标,支持coordinated omission,具有多种输出格式和报告选项
这些功能每一个都有单独的重要价值。当把它们合在一起时,他们将形成一个功能强大的工具包,使性能测试对每个人来说都变得更轻松。NoSQLBench使我们能够专注于测试需求,而不用在测试工具上做出妥协。
这也意味着我们可以避免创建昂贵而复杂的一次性测试工具。在实践中,这些一次性的工具通常有严重的缺陷。毕竟,构建各方面都考虑周全的测试工具并非易事。我们希望通过提供一种工具,它既可以简化处理所有困难的部分而又不剥夺使用者的控制权。
性能测试工具需要一段时间才能在测试人员的工具箱中赢得一席之地。值得庆幸的是,无论是对于DataStax还是客户,NoSQLBench都已证明自己是无价的工具。
核心概念
NoSQLBench的工作负载都被整合在一个YAML配置文件中。工作负载主要基于语句(statements),而YAML格式强调出了这一点。您也可以通过在这些语句中添加绑定(bindings)来指定用于操作的数据。为了组织和选出起作用的语句,您可以添加标签(tags)。语句还可以有针对特定语句的参数(params),比如是否将某一操作标记为幂等操作,或者是否使用预处理语句(prepared statement)等等。
Hello World
本教程是一个针对基础NoSQLBench工作流程的高阶介绍。您可以将其作为进行任何级别测试的基本模板。如果您的测试需要更多具体的细节,您可以在此基础上进行增添。假设您想用CQL向一个目标系统写入10亿条记录,您将需要使用cql驱动程序。
# hello-world-dml.yaml statements: - example: | insert into hello.world (cycle,name,sample) values ({cycle},{cyclename},{sample}); bindings: cycle: Identity() cyclename: NumberNameToString() sample: Normal(100.0D, 10.0D)
既然我们有了开始,接下来我们怎么能知道它会做我们想做的事情呢?
您可以一步一步地预览语句可能呈现的样子。以下是stdout驱动程序诠释此配置后生成的一些语句:
nb run driver=stdout yaml=hello-world-dml.yaml cycles=5 # output Logging to logs/scenario_20200403_101645_863.log insert into hello.world (cycle,name,sample) values (0,zero,95.30390911280935); insert into hello.world (cycle,name,sample) values (1,one,104.73915634900615); insert into hello.world (cycle,name,sample) values (2,two,112.3236295086616); insert into hello.world (cycle,name,sample) values (3,three,111.38872920562173); insert into hello.world (cycle,name,sample) values (4,four,91.52878591168258);
好的,我们已经有一些可用的东西了!您所看到的是使用stdout驱动程序执行一个活动(activity)的结果。这个驱动程序不使用任何传输协议,但是它可以将呈现出来的操作打印到控制台以供诊断。想要熟悉数据绑定,这是一种非常常见的方法。如果您针对Apache Cassandra数据库运行工作负载的话,这也是一种快速检查工作负载将执行哪些操作的方法。为此,您所需要做的就是将driver = stdout更改为driver = cql并提供一个可以连接的主机。
这显示了在测试场景中拥有一组通用概念和配置原语的强大所在。虽然这并不意味着不同的系统能够奇迹般地使用彼此的语句形式和协议,但这确实意味着您可以用一种惯用的方式表达它们,并根据目标系统定制您的测试。NoSQLBench高级驱动程序(如cql)的工作是将语句模板调整为您正在使用的协议形式。对于严肃的测试来说,如果性能测试工具不允许您使用目标系统的原生语言来控制访问模式和访问操作,那么它一定是无用的。
输出中的每一行表明每个操作的周期数是特定的,这也是每个操作所使用数据的基础。
如果您将达到这种效果所花费的精力与其他任何测试工具进行比较,您就会明白我们为什么要努力构建这个工具包。继续阅读下去,您使用NoSQLBench的原因会越来越多!
下一个级别
那么,我们如何利用上面的简单语句,并把它转换成易得易用的工具呢?我们需要允许使用者建立一个完整的测试场景,包括DDL。幸好这很容易做得到,因为在NoSQLBench中没有什么语句形式是不能使用的。您只需创建语句来定义您的键空间(keyspace)和模式(schema):
下面是我们模式中的工作负载配置:
# hello-world-ddl.yaml statements: - create-keyspace: | create keyspace if not exists hello WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'}; params: prepared: false - create-table: | create table if not exists hello.world ( cycle bigint, name text, sample double, primary key(cycle) ); params: prepared: false
这里显示了两个没有绑定的语句(DDL不需要绑定),以及一个被称为语句参数(statement parameter)的新YAML元素。prepared: false语句设置禁止自动使用预处理语句,因为您不能对DDL执行此操作。
现在我们有两个语句块,只要我们将它们保存在单独的文件中就可以了。然而,我们还可以做得更好。NoSQLBench YAML格式已经被改进,以支持不同类型的测试结构,包括块、标签和默认值。它仍然是YAML,但是NoSQLBench知道如有效地将这些层组合在一起:
# hello-world.yaml bindings: cycle: Identity() cyclename: NumberNameToString() sample: Normal(100.0D, 10.0D) randomish_cycle: HashRangeScaled() blocks: - tags: phase: schema params: prepared: false statements: - create-keyspace: | create keyspace if not exists hello WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'}; - create-table: | create table if not exists hello.world ( cycle bigint, name text, sample double, primary key(cycle) ); - tags: phase: main statements: - insert-sample: | insert into hello.world (cycle,name,sample) values ({cycle},{cyclename},{sample}); ratio: 4 - read-sample: | select * from hello.world where cycle={randomish_cycle} ratio: 1
这个版本中的新元素如下:
- 绑定部分没有直接附加到insert-sample语句: 由于insert-sample语句模板中的名称引用了全局文档范围中提供的绑定名称,所以会使用它们。任何没有引用的绑定都只是作为一个可选项存在,但并没有被使用。如果没有使用,它就不会被激活。
- 引入了语句块(statement blocks):这是组织语句的一种方式,以便您将它们打包进行配置和引用。第一个块中的所有DDL语句都有一个语句参数prepared: false
- 使用语句标签 (statement tags): 这允许我们选择起作用的语句,我们将在下一节中演示。第一个块中定义的所有语句都具有块级配置,带有标签phase: schema。第二块中的所有语句(仅一个)都有标签 phase: main。
- 添加了一个新语句来实现读取操作:实现randomish_cycle绑定(binding)的函数将生成一个介于0和当前操作周期之间的值。
- 为了演示的目的,添加了一些比率:按照上述比率,每5次操作中插入操作占4次,读取操作为第5次。为每个周期选择的语句也是基于这个比率。
由于我们已经将不同类型的语句组织到测试工作流程的不同部分中,我们就可以分别调用它们了。
注意:在YAML文件中,正确的缩进是很重要的。第一次使用YAML的用户经常会纠结这个问题。确保使用空格键而不是tab键,并将所有子元素缩进到比父元素靠后的位置。如果您从未使用过YAML,那么在构建更高级的场景之前先熟悉一下YAML为好。我们推荐Eric Goebelbecker的《YAML Tutorial: Everything You Need to Get Started in Minutes》一文。
创建模式(带有标签)
本节要求您拥有一个CQL系统用来连接。如果您还没有,您可以用下面的指令启动DSE实例:
docker run -e DS_LICENSE=accept --name my-dse -p 9042:9042 -d datastax/dse-server:6.7.7
我们来创建模式。
nb run driver=cql yaml=hello-world tags=phase:schema host=host # output Logging to logs/scenario_20200205_013213_767.log
注意,这里没有命令行输出。这是因为NoSQLBench假定除非您指定,您不希望被细节所困扰。如果您确实想查看详细信息,则可以添加一个-v来将命令行日志记录级别从警告WARNING级别提高到信息INFO级别,或者添加-vv来提高到DEBUG调试级别。
更进一步
我们现在还可以执行一些DML操作:
nb run driver=cql yaml=hello-world tags=phase:main host=host cycles=1M # output 01:53:23.719 [scenarios:001] WARN i.e.activityimpl.SimpleActivity - For testing at scale, it is highly recommended that you set threads to a value higher than the default of 1. hint: you can use threads=auto for reasonable default, or consult the topic on threads with `help threads` for more information. ^C (I hit control-C to interrupt it.)
NoSQLBench提醒我们增加线程。很好。让我们顺便再加一个参数,把grafana的图表功能也用起来。这个参数得益于NoSQLBench内部通过Docker容器集成的Prometheus, Grafana和Graphite Exporter环境。
nb run driver=cql yaml=hello-world tags=phase:main host=host cycles=1B threads=20x --docker-metrics # output Logging to logs/scenario_20200205_015849_242.log # every minute you'll see a progress indicator hello-world: 0.36%/Running (details: min=0 cycle=3589475 max=1000000000) hello-world: 0.67%/Running (details: min=0 cycle=6734460 max=1000000000) hello-world: 0.98%/Running (details: min=0 cycle=9777225 max=1000000000)
对于-docker-metrics,在测试场景开始之前,一个docker应用栈会在本地生成,并且所有指标都已预先配置好以便自动进入该应用栈。我们刚开始关注到这个特别的功能就已经能感受到它的有用之处了。
下面是它呈现的样子:
如果需要,您还可以用其他格式获得您的结果。如果您查看了nb help的输出,您会看到各种报告指标的方法,包括graphite、HDR logs、CSV等等。
具名场景
如果您希望每个人只需要一个命令就能够运行您的工作负载,包括模式设置和主阶段,您可以这样做。NoSQLBench新添加的一个名为named scenario的特性允许您以如下形式将命令嵌入到workload YAML中:
# add this to hello-world.yaml scenarios: default: ddl: run driver=cql tags==phase:schema threads==1 cycles==2 dml: run driver=cql tags==phase:main threads=auto cycles=1M
有了这个,你可以运行如下命令来从头到尾运行测试:
nb hello-world host=host
最终的结果是使用了命名场景中的两个模板化命令,只要它们没有被“==”锁定,命令行上的任何选项都会覆盖它们。当然,您仍然可以使用-docker-metrics和其他选项。您还可以使用default之外的名称来编写不同的命名场景,并将它们作为工作负载yaml文件以外的第二个选择器进行传递。这是一个相对较新的特性,但它已经用于将一系列常见工作负载集成到NoSQLBench中。
现在动手吧
您可以在这里访问NoSQLBench文档:http://docs.nosqlbench.io/.
您还可以使用docserver模式访问作为工具组成部分的NoSQLBench文档。有了这个工具附带的文档,您永远不会纳闷这些文档是否属于您使用的版本。这种模式也是UI功能在NoSQLBench中的应用。
您可以使用docker命令启动docserver模式,如下所示:
docker run --rm -a STDOUT --net=host --name nb-docs nosqlbench/nosqlbench docserver http://0.0.0.0:12345/ # output Started documentation server at http://0.0.0.0:12345/# or nb docserver # output Started documentation server at http://localhost:12345/
然后,您可以在启动它的系统上的一个网络连通的地址看到它。
要完全掌控NoSQLBench场景,需要了解一些活动参数(比如线程)。强烈建议新用户在指南中阅读基本的活动参数。
获取NoSQLBench
您可以在这个网址下载NoSQLBench的最新版本:https://github.com/nosqlbench/nosqlbench/releases
展望
NoSQLBench一直在改进。首先必须构建NoSQLBench的核心机制,而下一代的改进将集中于使用户更容易使用NoSQLBench。我们期待着看到以下进步:
- 改进的文档
- 改进的内置案例
- 更多的驱动程序
- 指南的用户界面
NoSQLBench允许您查看在使用或不使用应用程序时数据库的执行情况。它使得迭代数据模型、测量基线性能和计划数据库的规模成为可能。
我们希望让所有人都能使用一套通用的概念和工具,不论你测试的是什么NoSQL数据库,都使得测试更加容易。为了实现这个目标,我们希望NoSQLBench所基于的工具集可以成为行业内NoSQL测试的事实标准。通过将NoSQLBench和CQL驱动程序作为开源发布,我们已经迈出了实现这一愿景的第一步。
测试愉快!