MongoDB单机性能 第一回

Mongodb 配合node.js 是最佳搭档,但如果不经过必要的测试就上线的话肯定会出现这样那样的问题,包括:“无法发挥出预想的性能”、“不了解sharding和replication是如何工作的“、”不知道如何监控才好“,”要如何做备份和恢复呢“,”安全性方面要如何考量“。这系列的文章就是为了解答此问题。

 

前言

mongodb对于新手是很友好的,安装简单,用户接口也因为JSON而显得很单纯。没有什么RDBMS相关知识的开发者也能开发出简单的应用。基于javascript开发,常常使用样本数据来指导开发,而一旦当真实数据开始大量产生后,就会出现”怎么不能发挥预想性能的问题“

”MongoDB由于是NOSQL所以速度很快“  , 这样的见解是很危险的。以mongodb为例,NOSQL的特点是“善于水平数据分配(Sharding),水平分片的话,请往往比单机要快!”  这虽然是事实,但单机的快慢仍和具体的调优/优化有关。另外,”因为是NOSQL所以就比RDBMS要快“ 这种想法是要不得的;如果不在实际的场景中去充分测试那么没有人能得出有价值的性能比较结论。

也可能会有人这么想:“那么为了提供整体性能,我们就一定要把sharding数据分片用起来啊!”

但实际大家可能会觉得意外的是,MongoDB的大原则其实是尽可能不要进行sharding。

MongoDB的sharding虽然看起来非常不错,似乎有必要为了提高性能而就sharding进行相关的应用设计,但使用起来其实并不简单。 特别是对已经sharding的数据进行备份的话,就较为困难了。

在MongoDB中如果不是特别复杂的查询,那么使用较为一般的硬件,不进行sharding,也可以达到每秒3000-10000个document的查询。    因此,如果不是太大规模的数据量,则没有必要进行sharding。实际使用mongodb的企业很大一部分并没有启用sharding。

因此在本讲座中关于MongoDB单体性能的阐述,我会试图仔细的说明。  第一回我们说明下 “到底是慢在哪里?”, 第二回则说明“为什么慢”。

 

要知道是什么原因引起了慢

 

要处理性能问题,第一要义是知道是什么原因引起了慢;我是为基础设施团队工作的,经常从应用团队哪里接到”数据库就是慢得不行,你快帮忙想想办法吧。“ 这要的拜托。  听到这样的问题,一个职业工程师的第一个反应应当是找出到底什么原因造成了慢。

具体而言,”是某一个特定的查询的响应速度满了吗?“ ”还是整体的数据库的处理能力低下?”  , 以及到底是“查询慢了,还是“事务慢了”。  比如,写入的响应时间明显变长了,那么此时去扩大物理内存,往往也得不到什么改善。

那么MongoDB到底是哪里慢了,让我们了解一些诊断的技巧。

 

首先来看看慢的查询

 

首先我们来看看最基本的找出缓慢查询的方法。  在MongoDB中默认情况下,耗时超过100ms以上的查询,会现在在mongod进程的后台日志中。   以下展示的是mongodb 3.0.中的一个慢查询日志的例子(在MongoDB 2.x中也几乎一样):

 

2015-07-10T04:09:01.113+0900 I COMMAND  [conn1] command test.$cmd command: insert { insert: "hoge", documents: [ { _id: ObjectId('559ec6cd959e8f181ae68153'), a: "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789..." } ], ordered: true } keyUpdates:0 writeConflicts:0 numYields:0 reslen:40 locks:{ Global: { acquireCount: { r: 2, w: 2 } }, Database: { acquireCount: { w: 2 } }, Collection: { acquireCount: { w: 2 } } } 120ms

 

上例中对于{a:”01234567890..”}这样一个较大document的插入,花费了120ms。则因为默认100ms慢查询阈值的原因将生成mongod.log下的记录。

 

如果想看到更详细的查询统计信息时,可以启用profiler; 通过启用profiler,在每一个dbs中,缓慢查询的信息江北储存到db.system.profile 这个collection,该collection会自动清理过久的信息。

 

下面是一个启用profiler的例子。

> db.setProfilingLevel(1)
{ "was" : 0, "slowms" : 100, "ok" : 1 }

> db.system.profile.find()

 

 

观察mongostat

即使观察慢查询也没有大发现的情况下,可能是全局性的缓慢,此时有必要检查全局的查询统计信息。 此时mongostat的数据就显得很有价值。 mongostat和mongod都在mongodb的MONGODB_HOME/bin下面。

执行mongostat的话,就可以实时观察到mongod进程的一些重要统计信息。这与linux上的vmstat很相似。

 

一下是mongodb 2.x上的mongostat执行的例子。

$./bin/mongostat 
connected to: 127.0.0.1
insert  query update delete getmore command flushes mapped  vsize    res ...
    40     *0     *0     *0       0     1|0       1    12g  24.4g    51m ...
    30     *0     *0     *0       0     1|0       0    12g  24.4g    52m ...
    32     *0     *0     *0       0     1|0       0    12g  24.4g    53m ...

 

观察上述数据,查询的并发数、内存使用量、所的情况等数据被列出来。mongostat这里列出的数据均是mongodb中较为重要的性能指标。mongostat列出的一些统计信息列:

  • inserts/s 每秒插入次数
  • query/s 每秒查询次数
  • update/s 每秒更新次数
  • delete/s 每秒删除次数
  • getmore/s 每秒执行getmore次数
  • command/s 每秒的命令数,比以上插入、查找、更新、删除的综合还多,还统计了别的命令
  • flushs/s 每秒执行fsync将数据写入硬盘的次数。
  • mapped/s 所有的被mmap的数据量,单位是MB,
  • vsize 虚拟内存使用量,单位MB
  • res 物理内存使用量,单位MB
  • faults/s 每秒访问失败数(只有Linux有),数据被交换出物理内存,放到swap。不要超过100,否则就是机器内存太小,造成频繁swap写入。此时要升级内存或者扩展
  • locked % 被锁的时间百分比,尽量控制在50%以下吧
  • idx miss % 索引不命中所占百分比。如果太高的话就要考虑索引是不是少了
  • q t|r|w 当Mongodb接收到太多的命令而数据库被锁住无法执行完成,它会将命令加入队列。这一栏显示了总共、读、写3个队列的长度,都为0的话表示mongo毫无压力。高并发时,一般队列值会升高。
  • conn 当前连接数
  • time 时间戳

以上解释来自于 http://tech.lezi.com/archives/290

mongostat 这里没有列出cpu使用率等信息,实际上cpu信息对于用户来说有太多更好的接口可以收集,mongostat更关注于mongodb自身的一些性能指标。

当性能下降出现时,主要关注以下几点

  • 是否比平时的查询量上升了
  • 是否比平时的缓存命中V领降低了
  • 是否比平时数据库的锁增多了

可能大家已经注意到了,要知道mongostat的哪些指标现在是否是“异常值” 就需要知道平时的“常规值”, 正式在平时了解了系统的日常指标,那么在问题发生时才能知道是否存在异常指标。 因此,推荐在平时收集mongostat的数据,将这些数据保存下来。  如果觉得漫画,可以使用mongodb inc公提供的MMS(mongodb management system)。 其他例如zabbix等监控工具若配合插件,也可以做到监控。

 

需要注意的是,在mongodb 2.x与mongodb 3.0对比mongostat在表达上略微有些区别。今后我们会详细介绍。

使用redhat rpm包管理工具来安装mongodb的时候,可能没有提供mongostat;此时可以安装mongodb-org-tools这个包来包含这些工具。

 

最后来谈谈mongotop

 

在明明无法从慢查询日志中找出明显的问题,mongostat也没有变化,但不知道为什么应用程序还是很慢时,就应当使用mongotop。 mongotop与mongod类似,可以在$MONGODB_HOME下找到。 mongotop依照实时负载由高到低的顺序来排列,与Linux的top相似。

以下是mongotop的执行例子:

$ ./bin/mongotop

ns                     total    read    write    2015-07-10T04:56:52+09:00
mydb.mycol              6ms     6ms      0ms
admin.system.roles      0ms     0ms      0ms
admin.system.version    0ms     0ms      0ms

ns                     total    read    write    2015-07-10T04:56:53+09:00
mydb.mycol             44ms    44ms      0ms
admin.system.roles      0ms     0ms      0ms
admin.system.version    0ms     0ms      0ms

 

总结

最初我们说明了mongodb单机性能重要性,为了找出慢的原因我们介绍了慢查询日志、mongostat、mongotop三种监控工具。 mongodb还有其他许多的调差工具,但如果能熟练掌握上述三个工具的话,那么90%的问题都能找到原因了, 第二回中我们将介绍查询变慢的原因,即为什么变慢。

Comment

*

沪ICP备14014813号-2

沪公网安备 31010802001379号