当前位置: 移动技术网 > IT编程>数据库>MongoDB > 记一次MongoDB性能问题(从MySQL迁移到MongoDB)

记一次MongoDB性能问题(从MySQL迁移到MongoDB)

2017年12月08日  | 移动技术网IT编程  | 我要评论
公司为这个项目专门配备了几台高性能务器,清一色的双路四核超线程cpu,外加32g内存,运维人员安装好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]

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

迁移工作需要导入旧数据。mongodb本身有一个工具可供使用,不过它只接受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()

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

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

询问了几个朋友,有人反映曾遇到过类似的问题,在他的场景里,问题的主要原因是系统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整数范围决定的。

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

mongo> use <db>
mongo> db.setprofilinglevel(1);

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

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

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

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

关于zone_reclaim_mode内核参数的说明,可以参考。

注:从mongodb1.9.2开始:mongodb会在启动时自动设置zone_reclaim_mode。

至于numa的含义,简单点说,在有多个物理cpu的架构下,numa把内存分为本地和远程,每个物理cpu都有属于自己的本地内存,访问本地内存速度快于访问远程内存,缺省情况下,每个物理cpu只能访问属于自己的本地内存。对于mongodb这种需要大内存的服务来说就可能造成内存不足,numa的详细介绍,可以参考。

理论上,mysql、redis、memcached等等都可能会受到numa的影响,需要留意。

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网