记一次MongoDB性能问题

标签: Technical MongoDB Performance | 发表时间:2011-08-09 23:14 | 作者:老王 Fstone
出处:http://huoding.com

最近忙着把一个项目从MySQL迁移到MongoDB,在导入旧数据的过程中,遇到了些许波折,犯了不少错误,但同时也学到了不少知识,遂记录下来。

公司为这个项目专门配备了几台高性能务器,清一色的双路四核超线程CPU,外加32G内存,运维人员安装好MongoDB后,就交我手里了,我习惯于在使用新服务器前先看看相关日志,了解一下基本情况,当我浏览MongoDB日志时,发现一些警告信息:

WARNING: You are running on a NUMA machine. We suggest launching mongod like this to avoid performance problems: numactl –interleave=all mongod [other options]

当时我并不太清楚NUMA是什么东西,所以没有处理,只是把问题反馈给了运维人员,后来知道运维人员也没有理会这茬儿,所以问题的序幕就这样拉开了。

迁移工作需要导入旧数据。MongoDB本身有一个mongoimport工具可供使用,不过它只接受json、csv等格式的源文件,不适合我的需求,所以我没用,而是用PHP写了一个脚本,平稳运行了一段时间后,我发现数据导入的速度下降了,同时PHP抛出异常:

cursor timed out (timeout: 30000, time left: 0:0, status: 0)

我一时判断不出问题所在,想想先在PHP脚本里加大Timeout的值应付一下:

<?php

MongoCursor::$timeout = -1;

?>

可惜这样并没有解决问题,错误反倒变着花样的出现了:

max number of retries exhausted, couldn’t send query, couldn’t send query: Broken pipe

接着使用strace跟踪了一下PHP脚本,发现进程卡在了recvfrom操作上:

shell> strace -f -r -p <PID>
recvfrom(<FD>,

通过如下命令查询recvfrom操作的含义:

shell> apropos recvfrom
receive a message from a socket

或者按照下面的方式确认一下:

shell> lsof -p <PID>
shell> ls -l /proc/<PID>/fd/<FD>

此时如果查询MongoDB的当前操作,会发现几乎每个操作会消耗大量的时间:

mongo> db.currentOp()

与此同时,运行mongostat的话,结果会显示很高的locked值。

我在网络上找到一篇:MongoDB Pre-Splitting for Faster Data Loading and Importing,看上去和我的问题很类似,不过他的问题实质是由于自动分片导致数据迁移所致,解决方法是使用手动分片,而我并没有使用自动分片,自然不是这个原因。

询问了几个朋友,有人反映曾遇到过类似的问题,在他的场景里,问题的主要原因是系统IO操作繁忙时,数据文件预分配堵塞了其它操作,从而导致雪崩效应。

为了验证这种可能,我搜索了一下MongoDB日志:

shell> grep FileAllocator /path/to/log
[FileAllocator] allocating new datafile ... filling with zeroes...
[FileAllocator] done allocating datafile ... took ... secs

我使用的文件系统是ext4(xfs也不错 ),创建数据文件非常快,所以不是这个原因,但如果有人使用ext3,可能会遇到这类问题,所以还是大概介绍一下如何解决:

MongoDB按需自动生成数据文件:先是<DB>.0,大小是64M,然后是<DB>.1,大小翻番到128M,到了<DB>.5,大小翻番到2G,其后的数据文件就保持在2G大小。为了避免可能出现的问题,可以采用事先手动创建数据文件的策略:

#!/bin/sh

DB_NAME=$1

cd /path/to/$DB_NAME

for INDEX_NUMBER in {5..50}; do
    FILE_NAME=$DB_NAME.$INDEX_NUMBER

    if [ ! -e $FILE_NAME ]; then
        head -c 2146435072 /dev/zero > $FILE_NAME
    fi
done

注:数值2146435072并不是标准的2G,这是INT整数范围决定的。

最后一个求助方式就是官方论坛了,那里的国际友人建议我检查一下是不是索引不佳所致,死马当活马医,我激活了Profiler记录慢操作:

mongo> use <DB>
mongo> db.setProfilingLevel(1);

不过结果显示基本都是insert操作(因为我是导入数据为主),本身就不需要索引:

mongo> use <DB>
mongo> db.system.profile.find().sort({$natural:-1})

问题始终没有得到解决,求人不如求己,我又重复了几次迁移旧数据的过程,结果自然还是老样子,但我发现每当出问题的时候,总有一个名叫irqbalance的进程CPU占用率居高不下,搜索了一下,发现很多介绍irqbalance的文章中都提及了NUMA,让我一下子想起之前在日志中看到的警告信息,我勒个去,竟然绕了这么大一个圈圈!安下心来仔细翻阅文档,发现官方其实已经有了相关介绍,按如下设置搞定:

shell> echo 0 > /proc/sys/vm/zone_reclaim_mode
shell> numactl --interleave=all mongod [options]

关于zone_reclaim_mode内核参数的说明,可以参考官方文档

至于NUMA的含义,简单点说,在有多个物理CPU的架构下,NUMA把内存分为本地和远程,每个物理CPU都有属于自己的本地内存,访问本地内存速度快于访问远程内存,缺省情况下,每个物理CPU只能访问属于自己的本地内存。对于MongoDB这种需要大内存的服务来说就可能造成内存不足,幸好可以选择关闭它。

注:NUMA的详细介绍,可以参考老外的文章

我使用的是MongoDB1.8.2,以后出了新版本的话在细节上可能会有差异,大家测试吧。


相关 [mongodb 性能 问题] 推荐:

记一次MongoDB性能问题

- Fstone - 火丁笔记
最近忙着把一个项目从MySQL迁移到MongoDB,在导入旧数据的过程中,遇到了些许波折,犯了不少错误,但同时也学到了不少知识,遂记录下来. 公司为这个项目专门配备了几台高性能务器,清一色的双路四核超线程CPU,外加32G内存,运维人员安装好MongoDB后,就交我手里了,我习惯于在使用新服务器前先看看相关日志,了解一下基本情况,当我浏览MongoDB日志时,发现一些警告信息:.

记一次MongoDB性能问题,附原理解析

- zffl - NoSQLFan
下面文章转载自火丁笔记,原作者描述了一次MongoDB数据迁移过程中遇到的性能问题及其解决方案,中间追查问题的方法和工具值得我们学习. 另外NoSQLFan还对作者略讲的问题产生原理进行了分析,希望对您有用. 最近忙着把一个项目从MySQL迁移到MongoDB,在导入旧数据的过程中,遇到了些许波折,犯了不少错误,但同时也学到了不少知识,遂记录下来.

mongodb性能测试

- - 数据库 - ITeye博客
1) Mongodb的非安全插入方式,在一开始插入性能是非常高的,但是在达到了两千万条数据之后性能骤减,这个时候恰巧是服务器24G内存基本占满的时候(随着测试的进行mongodb不断占据内存,一直到操作系统的内存全部占满),也就是说Mongodb的内存映射方式,使得数据全部在内存中的时候速度飞快,当部分数据需要换出到磁盘上之后,性能下降很厉害.

MongoDB智能查询优化的问题

- - NoSQLFan
自动 查询优化是 MongoDB一个专门设计的功能. 简言之,这个功能就是通过对查询进行分析,从而判断出更有利的索引使用策略. 而这个智能的功能,实际潜伏着一些问题. 传统的查询优化是通过对语句进行语义分析来进行索引使用的预判,而MongoDB使用了一种更简单粗暴的方式,对查询的实际执行情况进行分析,它同时执行多条查询,每一条查询使用不同的索引,当其中一条返回时,终止其它的查询,并记录这次的结果,以后会优先使用返回更快的索引.

mongodb索引讲解与性能调优

- - haohtml's blog
mongodb索引规则基本上与传统的关系库一样,大部分优化MySQL/Oracle/SQLite索引的技巧也适用于mongodb. 当查询中用到某些条件时,可以对该键建立索引,以提高查询速度. 如果数据量很多且查询多于更新时,可以用索引提高查询的速度. a)         查询索引:. 查询索引很简单,比如说需要查询mailaccess数据库中的Mail collection上的索引时:.

Cassandra HBase和MongoDb性能比较

- - 数据库 - ITeye博客
这是一篇基于亚马逊云平台上对三个主流的. NoSQL数据库性能比较,在读写两个操作不同的组合情况下性能表现不同. 横坐标是吞吐量,纵坐标是延迟,这是一对矛盾,吞吐量越大,延迟越低,代表越好. 纯粹插入,Cassandra领先,见下图:. 2.WorkloadA: 读修改操作各占一半情况下的修改性能:MongoDB明显延迟增加,落败:.

[Cacti] mongodb性能监控实战

- - CSDN博客数据库推荐文章
          为了更好的使用mongodb,需要监控出mongodb的一些基础使用情况,比如Flush数、连接数、内存使用率、Index操作,Slave延迟等等,这些可以通过配置cacti监控mongodb的模板来完成. 1,在cacti界面导入模板 在计算机本地,下载此tgz包:http://mysql-cacti-templates.googlecode.com/files/better-cacti-templates-1.1.8.tar.gz.

开发高性能的MongoDB应用—浅谈MongoDB性能优化 - 吴纹羽

- - 博客园_首页
大数据时代的数据存储,非关系型数据库MongoDB(一).   “如何能让软件拥有更高的性能. ”,我想这是一个大部分开发者都思考过的问题. 性能往往决定了一个软件的质量,如果你开发的是一个互联网产品,那么你的产品性能将更加受到考验,因为你面对的是广大的 互联网用户,他们可不是那么有耐心的. 严重点说,页面的加载速度每增加一秒也许都会使你失去一部分用户,也就是说, 加载速度和用户量是成反比的.

三招解决MongoDB的磁盘IO问题

- - NoSQLFan
有点标题党的意思,不过下面三招确实比较实用,内容来自 Conversocial公司的VP Colin Howe在London MongoDB用户组的一个分享. 申请:下面几点并非放四海皆准的法则,具体是否能够使用,还需要根据自己的应用场景和数据特点来决定. 我们知道MongoDB是一个文档数据库,其每一条记录都是一个JSON格式的文档.

Mongodb亿级数据量的性能测试

- - haohtml's blog
进行了一下Mongodb亿级数据量的性能测试,分别测试如下几个项目:.  (所有插入都是单线程进行,所有读取都是多线程进行). 1) 普通插入性能 (插入的数据每条大约在1KB左右). 2) 批量插入性能 (使用的是官方C#客户端的InsertBatch),这个测的是批量插入性能能有多少提高. 3) 安全插入功能 (确保插入成功,使用的是SafeMode.True开关),这个测的是安全插入性能会差多少.