(9)异步Mongo驱动的性能测试——响应式Spring的道法术器

本系列文章索引《响应式Spring的道法术器》
前情提要 Spring WebFlux快速上手 | Spring WebFlux性能测试 | Spring WebClient性能测试
本文源码react

1.4.4 同步与异步数据库驱动的性能对比

许多数据库已陆续推出官方的异步驱动,在Spring Data Reactive中,已经集成了Mongo、Casandra、Redis、CouchDB的异步驱动。git

在Spring WebFlux中使用 Reactive Mongo的示例见Spring WebFlux快速上手github

这一节咱们经过使用YSCB对MongoDB的同步和异步驱动的性能基准测试,来观察异步驱动的优点。mongodb

YCSB(Yahoo! Cloud Serving Benchmark)是雅虎开源的一款用于测试各种云服务/NoSQL/键值对存储的性能基准测试工具。YCSB很赞,使用起来很简单,咱们就按照wiki介绍来操做便可。shell

1)准备YCSB数据库

若是使用Windows,请参考这里来预先安装必要的软件和工具。bash

获取YCSB有两种方式,一种是直接下载压缩包:网络

curl -O --location https://github.com/brianfrankcooper/YCSB/releases/download/0.12.0/ycsb-0.12.0.tar.gz
tar xfvz ycsb-0.12.0.tar.gz
cd ycsb-0.12.0

另外一种是基于源码构建:session

git clone git://github.com/brianfrankcooper/YCSB.git
cd YCSB
mvn clean package

此时就可使用bin/ycsb命令来进行性能测试了,运行一下:多线程

usage: bin/ycsb command databse [options]

Commands:
    load        Execute the load phase
    run         Execute the transaction phase
    shell       Interactive mode

...

从上边的命令帮助能够看到,咱们能够运行三种命令:

  • load,执行数据加载,也就是向数据库保存数据;
  • run,执行事务,好比更新、查询等;
  • shell,能够交互式地运行测试。

本节的测试主要用到load和run来进行数据的批量操做,先用load命令加载数据集,而后使用run命令测试数据操做。在YCSB中,测试的工做量由workload文件来定义。咱们看到在workloads下有workload[a-f]几个配置文件,好比workloada:

# Yahoo! Cloud System Benchmark
# Workload A: Update heavy workload
#   Application example: Session store recording recent actions
#                        
#   Read/update ratio: 50/50
#   Default data size: 1 KB records (10 fields, 100 bytes each, plus key)
#   Request distribution: zipfian

recordcount=1000
operationcount=1000
workload=com.yahoo.ycsb.workloads.CoreWorkload

readallfields=true

readproportion=0.5
updateproportion=0.5
scanproportion=0
insertproportion=0

requestdistribution=zipfian

可见配置文件定义了记录条数、操做次数、以及不一样的操做所占的百分比。好比上边readproportionupdateproportion都是50%,从注释也能够看出来,这模拟的是一种更新操做比较频繁的场景,能够模拟Web应用中保存session的场景。

几个workload的配置经过不一样的read/update/scan/insert操做比例来模拟不一样的场景。

咱们能够经过以下命令对mongo运行基于workloada的load阶段的性能测试:

bin/ycsb load mongodb -P workloads/workloada

默认是链接localhost:27017的mongodb数据库,若是但愿指定数据库链接信息,能够用-p参数指定:

bin/ycsb load mongodb -P workloads/workloada \
-p "mongodb.url=mongodb://192.168.0.101:27017/ycsb?w=1&maxPoolSize=32&waitQueueMultiple=20"

同时还指定了链接池最大数量和最多等待数量。

固然咱们也能够经过命令参数覆盖workloada文件中的数值,好比:

bin/ycsb load mongodb -P workloads/workloada \
-p "mongodb.url=mongodb://192.168.0.101/ycsb?w=1&maxPoolSize=32&waitQueueMultiple=20"  \
-p recordcount=10000 -p operationcount=10000 -threads 20

此外,还用-threads指定了并发线程数为20。

以上这些是本次测试会用到的内容,其余更多关于YCSB的使用请参考wiki吧。

2)准备测试

本次测试的目标是对比Mongodb同步和异步驱动的性能,简单起见,从吞吐量平均操做时长两个数据来衡量。纵向上,

  • 比较不一样数量的并发线程对两个数据的影响;
  • 观察测试时的链接数变化。

链接数的变化能够经过mongostat命令来观察,以下图所示:

title

上边运行的mongo-benchmark.sh是基于bin/ycsb命令编写的方便测试的脚本,并输出一些汇总数据(包括吞吐量和平局操做时长)方便查看,同时也会将每次bin/ycsb命令输出的详细内容保存到output目录下的文件中。
脚本能够在代码库中找到,若是mongo运行于localhost:27017,可直接用以下命令执行(在与bin同目录下):

curl https://raw.githubusercontent.com/get-set/get-reactive/master/ycsb-mongo-shell/mongo-benchmark.sh | bash

图中上方是对同步驱动和异步驱动各自跑了一次基于workloada的load和run的测试,下方是mongostat的输出(每秒输出一行),从insertqueryupdate的数字能够找出四个橘×××的框标出的4个阶段。经过这些数据咱们能够分析出:

  • load主要是加载数据集,所以会看到insert的数字增多,加起来是测试预设的30000条数据;相似的run主要是进行基于workload的操做测试,workloada是50/50的read/update,在mongostat的输出中也有体现。
  • load阶段同步和异步驱动的吞吐量分别为19801和25554,run阶段同步和异步的吞吐量分别为25706和27675,同步驱动略逊一筹;再观察insert、read和update操做的平均时长,能够得出一样的结论。
  • 此次测试设置了20个线程对mongo数据库进行操做,在mongostat输出的conn列能够看到数据库链接个数的变化,对于同步的驱动来讲,链接个数会从4个增长到25个,而对于异步的驱动来讲,链接个数会从4个增长到7个。

经过这种方式,针对不一样的线程数,观察两种驱动的性能数据并经过mongostat的数据记录链接数。

1、不限制链接数

为了观察链接数的变化,先不限制maxPoolSize(注释脚本中MAX_POOL_SIZE=8那一行)。最终结果以下:

title

图中,每种颜色的左列和右列分别是同步和异步的数据。直观起见,咱们经过图表来对比一下:

首先对比一下load阶段和run阶段的吞吐量(柱越高越好)

title

title

能够发现,当线程数达到8个以后,吞吐量的增加趋势基本消失了,尤为是同步驱动的吞吐量还会随线程数的继续增长而略有降低。不知是否跟测试环境为四核八线程的CPU有关系。

而后对比一下INSERT、READ和UPDATE操做的平均时长(柱越低越好)

title

title

title

相对来讲,异步驱动能带来更快的读写操做,尤为是应对愈来愈多的线程的时候。

最后对比一下链接数

链接数的对比更加明显:对于同步的状况,链接数=线程数+5;而对于异步的状况,链接数几乎一直保持在7个。没有对比就没有伤害呀。

2、限制链接数

下面,将链接数限制为32个,测试一下线程数从30-80的状况下,同步驱动的性能数据:

title

经过图表对比:

title

title

title

title

title

可见,限制链接数以后,略有改善,可是相比异步驱动来讲,仍然有必定差距。

3)结论

首先,须要说明的是,以上并不是是以数据库调优为目的的测试,这里咱们只测试了workloada(若是你感兴趣能够将脚本中的WORKLOAD变量修改一下,而后测试其余场景),并且限制链接数为32并无特别的依据,对测试的机器来讲,32也并不是最优的链接数。

经过本节的测试,针对MongoDB驱动咱们能够得出如下两个结论:

  • 相对于同步驱动来讲,异步驱动在性能方面略胜一筹;
  • 在应对大量客户端线程的状况下,异步驱动可以以少许而稳定的链接数应对,意味着更少的内存消耗(每一个链接消耗stack size的内存空间,默认状况下stack size为10M)。

1.4.4 总结

上边咱们分别针对Http服务端Http客户端以及数据库进行了同步和异步的测试对比,综上来看,基于异步非阻塞的响应式应用或驱动可以以少许且固定的线程应对高并发的请求或调用,对于存在阻塞的场景,可以比多线程的并发方案提供更高的性能。

响应式和非阻塞并非总能让应用跑的更快,何况将代码构建为非阻塞的执行方式自己还会带来少许的成本。可是在相似于WEB应用这样的高并发、少计算且I/O密集的应用中,响应式和非阻塞每每可以发挥出价值。尤为是微服务应用中,网络I/O比较多的状况下,效果会更加惊人。

相关文章
相关标签/搜索