MongoDB性能测试

Nodejs编写的应用,后端连MongoDB进行持久化存储。Mongodb分别有两个版本,分别跑在虚拟机和kubernetes里面,进行读写性能测试

测试基线

分别在虚拟机和K8S中安装Mongodb数据库,版本为4.0.18,测试目标为考察mongodb跑在虚拟机和K8S中的性能差异

  • 虚拟机配置:2C4G
  • K8S中的pod配额(limits)为2C4G,mongodb后端挂接ceph rbd存储

压力测试使用的软件为wrk,地址为:https://github.com/wg/wrk。这里推荐一下wrk,可以以极少的线程模拟出高并发的场景,比之前用的ab好用了不是一点。

Node性能测试

首先我们来看下node的基础性能测试,众所周知nodejs是异步非阻塞的编程模型,在处理高并发场景有天然优势,这边我们测试一下,在不接后端数据库的情况下,纯nodejs处理(比如请求校验错误),性能可以到多少。node应用也是跑在k8里的,设置的配额(limits)为6C,并发数设置为200:

[root@dce304-cal-vm3 ~]# wrk -c 200 -T 30s -s demo.lua http://22.196.66.200:31010/users
Running 10s test @ http://22.196.66.200:31010/users
  2 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    61.84ms   26.29ms 479.18ms   94.73%
    Req/Sec     1.65k   209.52     2.03k    85.00%
  32905 requests in 10.01s, 8.38MB read
  Non-2xx or 3xx responses: 32905
Requests/sec:   3287.93
Transfer/sec:    857.30KB

可以看到QPS在3200多,而且这个数值是线性增长的,即如果起两个实例,则QPS可以到6000多,3个实例的话可以到9000多。记住这个数据,这是后面进行比较的基础(单个node的最高性能,也就是加上数据库以后理论上也不会超过这个QPS)

虚拟机Mongo实例测试

node后端接入跑在虚拟机上的mongodb实例(mongo本身均为单实例,未做集群),我们来看一下:

写入测试

单node副本

[root@dce304-cal-vm3 ~]# wrk -c 200 -T 30s -s demo.lua http://22.196.66.200:31010/users
Running 10s test @ http://22.196.66.200:31010/users
  2 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   810.15ms    1.62s    9.80s    88.46%
    Req/Sec   317.73    113.81   727.00     71.36%
  6323 requests in 10.02s, 3.41MB read
Requests/sec:    631.35
Transfer/sec:    348.95KB

cpu使用率为20%

2个node副本

[root@dce304-cal-vm3 ~]# wrk -c 200 -T 30s -s demo.lua -d 30s http://22.196.66.200:31010/users
Running 30s test @ http://22.196.66.200:31010/users
  2 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   176.34ms  266.36ms   3.79s    97.12%
    Req/Sec   710.32    168.50     1.01k    63.83%
  42445 requests in 30.03s, 22.91MB read
Requests/sec:   1413.36
Transfer/sec:    781.11KB

cpu使用率为40%

5个node副本

[root@dce304-cal-vm3 ~]# wrk -c 200 -T 30s -s demo.lua -d 30s http://22.196.66.200:31010/users
Running 30s test @ http://22.196.66.200:31010/users
  2 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    60.30ms   35.27ms   1.06s    96.79%
    Req/Sec     1.71k   236.41     2.18k    76.83%
  102166 requests in 30.02s, 55.12MB read
Requests/sec:   3403.58
Transfer/sec:      1.84MB

cpu使用率为60%

写入测试总结

总体来说随着副本数增加,整体性能呈线性增加,5副本时mongo数据库的cpu也只有60%,应该说还有余量。应该是mongodb默认的连接池的限制起了作用(默认连接数为5个)

读取测试

数据库中放置测试数据780万条,根据ObjectId关键字进行查询:

单node副本

[root@dce304-cal-vm3 ~]# wrk -c 200 -T 30s http://22.196.66.200:31010/users/5ecb83b3c5299b002bf8bd09
Running 10s test @ http://22.196.66.200:31010/users/5ecb83b3c5299b002bf8bd09
  2 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   726.33ms    1.46s    8.79s    88.23%
    Req/Sec   524.42    158.59     1.00k    72.00%
  10448 requests in 10.01s, 5.59MB read
Requests/sec:   1043.39
Transfer/sec:    572.14KB

cpu利用率16%

5个node副本

[root@dce304-cal-vm3 ~]# wrk -c 200 -T 30s -d 30s http://22.196.66.200:31010/users/5ecb83b3c5299b002bf8bd09
Running 30s test @ http://22.196.66.200:31010/users/5ecb83b3c5299b002bf8bd09
  2 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    33.17ms   18.24ms 584.77ms   87.45%
    Req/Sec     3.10k   303.76     3.64k    85.17%
  184886 requests in 30.01s, 98.91MB read
Requests/sec:   6159.80
Transfer/sec:      3.30MB

cpu利用率63%

读取测试总结

读取方面,因为有缓存的关系(命中率较高),整体的QPS比写入还略高,基本也是随副本数呈线性增长的态势。

kubernetes mongo 实例测试

接下来我们测试一下,mongodb跑在k8s中,后端挂ceph块存储的性能(k8的work与ceph集群连接为千兆网卡)

写入测试

单node副本

[root@dce304-cal-vm3 ~]# wrk -c 500 -s demo.lua -T 30s http://22.196.66.200:31010/users
Running 10s test @ http://22.196.66.200:31010/users
  2 threads and 500 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   470.51ms    1.13s    9.77s    93.67%
    Req/Sec   398.62    150.61     0.91k    71.81%
  7654 requests in 10.02s, 4.13MB read
Requests/sec:    763.54
Transfer/sec:    422.03KB

cpu使用率 13.7%

2个node副本

[root@dce304-cal-vm3 ~]# wrk -c 200 -s demo.lua -T 30s http://22.196.66.200:31010/users
Running 10s test @ http://22.196.66.200:31010/users
  2 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   281.70ms  628.13ms   5.50s    93.31%
    Req/Sec   738.18    142.56     1.14k    79.50%
  14710 requests in 10.01s, 7.94MB read
Requests/sec:   1468.87
Transfer/sec:    811.73KB

cpu使用率25%

5个node 副本

[root@dce304-cal-vm3 ~]# wrk -c 200 -s demo.lua -T 30s http://22.196.66.200:31010/users
Running 10s test @ http://22.196.66.200:31010/users
  2 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    61.27ms   29.67ms 453.58ms   83.79%
    Req/Sec     1.66k   233.53     2.09k    93.00%
  33091 requests in 10.02s, 17.85MB read
Requests/sec:   3303.79
Transfer/sec:      1.78MB

cpu使用率57%

写入测试总结

可以看到使用网络存储和本地磁盘,在写入性能上基本没有区别,在单副本情况下,使用rbd的性能甚至还好于本地磁盘。

读取测试

单node 副本

[root@dce304-cal-vm3 ~]# wrk -c 200 -T 30s http://22.196.66.200:31010/users/5ecba669f41c9b002b91cfbc
Running 10s test @ http://22.196.66.200:31010/users/5ecba669f41c9b002b91cfbc
  2 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   564.36ms    1.19s    7.58s    89.28%
    Req/Sec   610.83    224.26     1.01k    58.38%
  12119 requests in 10.02s, 6.49MB read
Requests/sec:   1210.00
Transfer/sec:    663.37KB

cpu使用率20%

5个node副本

[root@dce304-cal-vm3 ~]# wrk -c 200 -T 30s http://22.196.66.200:31010/users/5ecba669f41c9b002b91cfbc
Running 10s test @ http://22.196.66.200:31010/users/5ecba669f41c9b002b91cfbc
  2 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    36.44ms   26.26ms 542.40ms   96.53%
    Req/Sec     2.91k   498.88     3.58k    87.00%
  58009 requests in 10.01s, 31.03MB read
Requests/sec:   5792.89
Transfer/sec:      3.10MB

cpu使用率91%

测试总结

可以看到,不管是跑在虚拟机中,还是k8s里,测试的结果是基本接近的。而按照我们的一般认知,本地磁盘的读写性能肯定还是要高于网络存储的,这里面的关键,还是要说到mongodb的读写机制。mongo作为一款典型的nosql数据库,其绝大部分的操作都是在内存中完成的。MongoDB把文档写进内存之后就返回了,所以说QPS基本不受后端存储性能的影响。

这边简单说一下mongodb数据存储的原理:

内存映射机制

Mongo使用了内存映射技术(mmap) - 写入数据时候只要在内存里完成就可以返回给应用程序,而保存到硬盘的操作则在后台异步完成。这也就是说,MongoDB并不对RAM和磁盘这两者进行区别对待,只是将文件看作一个巨大的数组,然后按照字节为单位访问其中的数据,剩下的都交由操作系统(OS)去处理。先了解一下Memeory-Mapped Files:
1、内存映射文件是OS通过mmap在内存中创建一个数据文件,这样就把文件映射到一个虚拟内存的区域。
2、虚拟内存对于进程来说,是一个物理内存的抽象,寻址空间大小为2^64
3、操作系统通过mmap来把进程所需的所有数据映射到这个地址空间(红线),然后再把当前需要处理的数据映射到物理内存(灰线)
4、当进程访问某个数据时,如果数据不在虚拟内存里,触发page fault,然后OS从硬盘里把数据加载进虚拟内存和物理内存
5、如果物理内存满了,触发swap-out操作,这时有些数据就需要写回磁盘,如果是纯粹的内存数据,写回swap分区,如果不是就写回磁盘。


mmap.png

Storage View

Mongodb有三个storage view:Share view,private view,journal日志,前两个位于内存中,后一个位于磁盘上。

  • Share view:位于内存上,会存储已经改变的要刷新到磁盘上的数据(脏数据)。Share view是唯一一个直接连映射到数据库文件上的view。当你启用mongoDB的日志功能时,mongod会请求操作系统把磁盘上的数据文件指向share view内存视图上。操作系统不会数据文件加载到share view中。Mongdb在需要时自己把数据文件加载到share view上。
  • Private view:位于内存上,存储用于读请求的数据,更改请求最先在这执行。MongDB把Private view指向share view。
  • Journal view:存储已经在private cache上发生更改的数据,但是会在更改数据刷新到 share view(cache) 之前存储。Journal 确保了数据的持久化。如果更改的数据没有刷新到磁盘上的数据文件里,mongodb crash了,当mongodb 起来以后,mongodb会把journallog中没应用到数据文件中的数据回放到 share view(cache) 中,最终会应用到数据文件中。

当一个写请求发生时:
1、更改 private view (cache)中的数据
2、默认每100毫秒刷新到journal log。journal log有一个记录当前日志点的pointer
3、应用journal log中的写操作到share view ,这时share view 就和数据文件不一致
4、默认每隔60秒,mongodb会请求操作系统刷新shared view中更改的数据到数据文件
5、mongdb会把journal log中记录更改数据日志点的pointer,以前的数据删除掉。
6、为了数据的一致性,Mongodb通常会请求操作系统重新把share view 指向private view。


image.png

所以说,在客户端连接数一定的情况下(使用mongoose情况下连接池默认为5),单个node实例占用的mongodb资源是固定的,性能也是接近的(都是操作内存),实测将k8s中的mongodb实例的内存配额调低到2GB,测出的性能没有太大差距,所以说mongo的性能和内存的关系不大(当然大内存会降低cpu的资源消耗)。

补充测试

既然前面提高了使用node连接mongo,默认连接池大小为5(数据库连接相关设置,请参考http://www.mongoosejs.net/docs/connections.html
),那么我们来测试一下,如果调整参数,是否会对于性能产生影响。仍然还是单node副本,数据库连接配置如下:

  config.mongoose = {
    client: {
      url: 'mongodb://22.196.66.200:31669/test',
      options: {
        user: 'test',
        pass: 'test',
        poolSize: 50,
      },
    },
  };

调整为50,测试结果如下:

[root@dce304-cal-vm3 ~]# wrk -c 200 -s demo.lua http://22.196.66.200:31010/users
Running 10s test @ http://22.196.66.200:31010/users
  2 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   188.41ms  111.62ms   1.87s    90.22%
    Req/Sec   316.79    126.13   626.00     70.90%
  6236 requests in 10.02s, 3.37MB read
  Socket errors: connect 0, read 0, write 0, timeout 85
Requests/sec:    622.50
Transfer/sec:    344.11KB

cpu使用率为13%
结果:增强pooSize大小对于QPS并没有实质性影响,最有效的增加性能的方式还是添加实例数。从测试结果来看,影响QPS的不是mongodb的连接数,而是nodejs的并发数限制,因为node本身是单进程模型,单进程能处理的并发数有限,不能充分利用cpu多核的优势。

为了进一步验证,我们把eggjs的工作线程workers的数量设置为4,重启pod进行测试:
[root@dce304-cal-vm3 ~]# wrk -c 200 -s demo.lua http://22.196.66.200:31010/users
Running 10s test @ http://22.196.66.200:31010/users
2 threads and 200 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 82.35ms 29.02ms 347.47ms 76.04%
Req/Sec 1.21k 285.20 1.76k 81.50%
24194 requests in 10.02s, 13.06MB read
Requests/sec: 2415.47
Transfer/sec: 1.30MB

可以看出来QPS马上变成原来的4倍,所以说影响nodejs性能的主要因素还是**线程数**

参考资料:
[http://blog.chinaunix.net/uid-25135004-id-3810200.html](http://blog.chinaunix.net/uid-25135004-id-3810200.html)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270