首页 » MongoDB实战 » MongoDB实战全文在线阅读

《MongoDB实战》10.4 性能调优

关灯直达底部

最后这一节里,我会提几个与诊断和解决性能问题相关的内容。

大多数MongoDB的性能问题都能追溯到一个源头:硬盘。本质上来看,对磁盘施加的压力越大,MongoDB就运行得越慢,因此大多数性能优化的目标就是减少对磁盘的依赖。有多种方式能达到这个目标,但在我们深入了解它们之前,先了解如何弄清磁盘性能还是很有必要的。在Unix类系统上,iostat就是一款理想的工具。以下示例中,我通过-x选项显示扩展统计信息,2说明以2 s为间隔进行显示:1

1. 注意,该示例是针对Linux的;在Mac OS X上,对应命令是iostat -w 2

$ iostat -x 2Device: rsec/s wsec/s avgrq-sz avgqu-sz await svctm %utilsdb 0.00 3101.12 10.09 32.83 101.39 1.34 29.36Device: rsec/s wsec/s avgrq-sz avgqu-sz await svctm %utilsdb 0.00 2933.93 9.87 23.72 125.23 1.47 34.13  

想要详细了解每一个字段的含义,请查看系统的man页面。要快速诊断问题,你会对最后三列最感兴趣。await以毫秒为单位,标明了处理I/O请求的平均时间,该平均值包含了I/O队列里的时间和实际处理I/O请求的时间。svctime标明了处理请求所花费的平均时间。%util则是CPU用来处理磁盘I/O请求所耗时间的百分比。

之前的iostat片段显示了一个中等程度的磁盘占用情况。I/O的平均等待时间大约是100 ms(提示:这已经不少了!),平均处理时间大约是1 ms,利用率大约是30%。如果查看该机上的MongoDB日志,你能看到很多慢操作(查询、插入或其他操作)。事实上,正是那些慢操作最早让你对潜在的问题有所警觉。iostat的输出能帮助你确认问题。请注意,MongoDB系统的磁盘利用率达到100%是很常见的;虽然仅由MongoDB的问题造成磁盘利用率高的情况很少,但这些用户还是觉得被MongoDB折腾得够呛。在后续的五个小节里,我会给出一些优化数据库操作、减轻磁盘负载的方法。

10.4.1 为提升性能检查索引和查询

发现性能问题时,应该首先检查索引。这里假设应用程序会发起查询和更新,它们是使用索引的主要操作。2第7章大致罗列了识别并修复慢操作的步骤;其中涉及开启查询剖析器,随后确保每个查询与更新都能有效利用索引。总的来说,这意味着每个操作要扫描尽可能少的文档。

2. 某些数据库命令,比如count,同样也会使用索引。

保证没有冗余的索引也同样重要,因为冗余索引会占用磁盘空间、消耗更多内存,在每次写入时还需要做更多工作。第7章中有消除此类冗余索引的方法。

然后呢?在审视了索引和查询之后,你会发现效率低下的部分,把性能问题一起修正掉。日志里再也看不到慢查询警告了,iostat的输出也显示利用率下降了。调整索引在修正性能问题方面的效果比你想的要好;在发现性能问题时,索引应该是你首先检查的地方。

10.4.2 添加内存

修改索引并非总是有效,也许你已经有了最优化的查询,有了完美的索引,但是磁盘利用率还是居高不下。此时,你应该看看索引尺寸和工作集对物理内存的比例。在应用程序所用到的每个数据库上运行stats命令:

> use app> db.stats{    /"db/" : /"app/",    /"collections/" : 5,    /"objects/" : 3932487,    /"avgObjSize/" : 543.012,    /"dataSize/" : 2135390324,    /"storageSize/" : 2419106304,    /"numExtents/" : 38,    /"indexes/" : 4,    /"indexSize/" : 226608064,    /"fileSize/" : 6373244928,    /"nsSizeMB/" : 16,    /"ok/" : 1}  

现在看一下数据和索引的大小,数据大小刚超过2 GB,索引大小大约是230 MB。假设工作集包含了系统中的全部数据,那么机器上至少要有3 GB内存才能避免频繁访问磁盘。要是这台机器只有1.5 GB内存,那你就只能眼睁睁看着磁盘利用率居高不下了。

在查看数据库统计信息时,还要注意dataSizestorageSize之间的区别。当storageSize超过dataSize两倍以上时,就会因磁盘碎片而影响性能。这些碎片会迫使服务器使用更多的内存;遇到这种情况,在添加更多的内存之前,应该先尝试压紧数据文件。请查看本章之前与压紧有关的内容,了解如何进行压紧。

10.4.3 提升磁盘性能

添加内存的方法也有一些问题。首先,并非总能添加内存,例如,你正在使用EC2,虚拟机的最大可用内存上限就是68 GB。其次,添加内存并非总能解决I/O问题。举例来说,如果应用程序是写密集型的,后台的刷新或者向内存加载新数据分页依然会压垮你的磁盘。所以说,如果有了高效的索引和充足的内存,但还是觉得磁盘I/O缓慢,就该想想提升磁盘性能了。

提升磁盘性能有两种方法。一种是购买更快的磁盘,买块15 K RPM的硬盘或者SSD还算是笔划算的投入。除此之外,把磁盘配置成RAID阵列,也能够提升读写的吞吐量,这种方式也可以作为前者的补充。3如果配置得当,RAID阵列也许可以解决I/O瓶颈。正如之前所说的那样,在EBS卷上运行RAID 10能显著提升读取的吞吐量。

3. RAID还有另一个好处,即在恰当的RAID级别下,能够获得磁盘冗余。

10.4.4 水平扩展

在解决性能问题时,下一步就该用到水平扩展了。你有两条路可选。如果应用程序是读密集型的,单个节点可能无法应对所有查询,即使内存中是优化后的索引和数据。这时可以让读操作分布在各个副本上。官方的MongoDB驱动支持跨副本集成员进行操作,在逐步提升到分片集群前,这个策略值得一试。

当所有其他手段都无效之时,就得进行分片了。满足以下条件时,你就应该转向分片集群了:

  • 无法将工作集完整加载到任意一台机器的物理内存里;

  • 对任意服务器而言,写负载太密集了。

要是在配置了分片集群之后,还是存在性能问题,那你就该回过头去,确保所有索引都经过了优化、数据都在内存里,并且磁盘性能良好。要获得最佳的硬件利用率,你可能需要添加更多分片。

10.4.5 寻求专业帮助

造成性能下降的原因多种多样,并且经常很奇特。从糟糕的Schema设计到诡异的服务器缺陷都能影响性能。如果在尝试了各种可能的办法之后,仍然无法解决问题,你应该考虑让对MongoDB更有经验的人士来检查你的系统。一本书的作用有限,但是经验丰富的专业人士所发挥的作用就大不相同了。当你不知所措或者心存疑虑时,请寻求专业帮助。性能问题的解决方案有时完全是凭直觉的。