一、 MongoDB 软件层面优化
1、设置WiredTiger的cacheSizeGB
通过cacheSizeGB选项配置控制WiredTiger引擎使用内存的上限,默认配置在系统可用内存的60%左右。
如果一台机器上只部署一个mongod,mongod可以使用所有可用内存,则使用默认配置即可。
如果一台机器上部署多个mongod,或者mongod跟其他的一些进程一起部署,则需要根据分给mongod的内存配额来配置cacheSizeGB,按配额的60%左右配置即可。
通过配置文件配置cacheSizeGB,如下:
2、分配足够的Oplog空间
Oplog是MongoDB local库下的一个固定集合,Secondary就是通过查看Primary 的oplog这个集合来进行复制的。Oplog可以说是MongoDB Replication的纽带。Oplog是固定大小的,它只能保存特定数量的操作日志。如果oplog size过大,会浪费存储空间;如果oplog size过小,老的oplog记录很快就会被覆盖,那么宕机的节点很容易出现无法同步数据的现象,因此设置合理的oplog大小对mongodb很重要。MongoDB默认将其大小设置为可用disk空间的5%(默认最小为1G,最大为50G)。
3、启用Log Rotation日志切换
防止MongoDB的log文件无限增大,占用太多磁盘空间。使用Log Rotation并及时清理历史日志文件,在配置文件配置如下红框设置。
logRotate:日志回转,防止一个日志文件特别大,可选值:rename,重命名日志文件,默认值;reopen,使用Linux日志rotate特性,关闭并重新打开次日志文件,可以避免日志丢失,但是logAppend必须为true。
timeStampFormat:指定日志格式的时间戳格式,可选值:ctime,显示时间戳Wed Dec 31 18:17:54.811;Iso8601-utc,显示时间戳以协调通用时间(UTC)在ISO-8601中的格式,例如,纽约时代的开始时间:1970-01-01t00:00: 00.000z;iso8601-local,显示当地时间ISO-8601格式显示时间戳。
4、设置journal日志刷新时间和flush时间
commitIntervalMs:mongod的journal日志刷新值范围从1到500毫秒。较低的值增加了journal的耐久性,以牺牲性能为代价,在WiredTiger引擎上,默认的日志提交间隔为100毫秒,增大commitIntervalMs可以降低磁盘的IO压力,起到一定的优化作用。不过一般情况下,不建议修改。
syncPeriodSecs:mongod使用fsync操作将数据flush到磁盘的时间间隔,默认值为60(单位:秒),增大该值也可以降低磁盘IO压力,起到一定优化作用。一般情况下,强烈建议不要修改此值。mongod将变更的数据写入journal后再写入内存,并间歇性的将内存数据flush到磁盘中,即延迟写入磁盘,有效提升磁盘效率。此指令不影响journal存储,仅对mongod有效。
二、 MongoDB 软件层面优化
1、MongoDB连接内存优化
MongoDB服务器内存要满足connection overhead + data size + index size,即连接数开销 + 热点数据 + 索引。
linux操作系统默认每个连接数占用10M内存。
使用ulimit -a 查看stack size,即为每个连接数占用的内存。
所有连接数消耗的内存加起来相当惊人,推荐把Stack设置小一点,比如说1024:在linux命令窗口输入ulimit -s 1024。这种方式的缺点是,重新打开一个shell命令窗口就失效啦,需要重新执行这一条命令。
永久生效的方式,修改/etc/profile,在最后添加ulimit -s 1024,
# Add for optimize
ulimit -s 1024
然后保存并source /etc/profile
2、MongoDB连接数优化
MongoDB连接数主要是通过提高操作系统的默认文件描述符和进程/线程数限制。Linux默认的文件描述符数和最大进程数对于MongoDB来说一般会太低。建议把这个数值设为100000以上。因为MongoDB服务器对每一个数据库文件以及每一个客户端连接都需要用到一个文件描述符。如果这个数字太小的话在大规模并发操作情况下可能会出错或无法响应。报以下错误信息:
"too many open files""too many open connections"
上面报错的信息,说明打开的连接数太多了,有两个限制mongod/mongos连接数的地方:
① 操作系统的ulimit限制,本节重点介绍;
② mongodb自身的限制;
操作系统的ulimit限制,可以用ulimit -a查看open files,是否够大。linux下默认的open files是1024,在提供服务的时候往往太小。
可以通过以下命令来修改这些值,暂时性,重新打开shell命令窗口会失效:
ulimit -n 1048576 ulimit -u 524288
这时可以通过修改/etc/security/limits.conf( 部分的系统是在/etc/security/limits.d/90-nproc.conf)持久化设置允许用户/进程打开文件句柄数,这一步需要重启系统,不然不起作用,在limits.conf添加如下设置:
vi /etc/security/limits.conf
* soft nofile 1048576
* hard nofile 1048576
* soft nproc 524288
* hard nproc 524288
3、关闭Transparent Huge Pages
Transparent Huge Pages(THP)是Linux的一种内存管理优化手段,通过使用更大的内存页来减少Translation Lookaside Buffer(TLB)的额外开销。MongoDB数据库大部分是比较分散的小量数据读写,THP对MongoDB这种情况会有负面的影响,所以建议关闭。
暂时性的做法,会失效:
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
永久性做法,修改/etc/rc.d/rc.local,添加如下设置:
vi /etc/rc.d/rc.local
if test -f /sys/kernel/mm/transparent_hugepage/enabled; then
echo never > /sys/kernel/mm/transparent_hugepage/enabled
fi
if test -f /sys/kernel/mm/transparent_hugepage/defrag; then
echo never > /sys/kernel/mm/transparent_hugepage/defrag
fi
4、使用XFS文件系统,同时禁掉数据库文件的atime
MongoDB在WiredTiger存储引擎下建议使用XFS文件系统。Ext4最为常见,但是由于ext文件系统的内部journal和WiredTiger有所冲突,所以在IO压力较大情况下表现不佳。
在使用XFS文件系统的同时,我们建议在文件系统的mount参数上加上noatime,nodiratime两个选项。用noatime mount的话,文件系统在程序访问对应的文件或者文件夹时,不会更行对应的access time。
5、使用SSD或RAID10来提供存储IOPS能力
MongoDB是一个高性能高并发的数据库,其大部分的IO操作为随机更新。一般来说本机自带的SSD是最佳的存储方案。如果使用普通的磁盘,建议使用RAID10条带化来提供IO通道的并发能力。
6、为Data和Journal/log分别使用单独的物理卷
MongoDB很多的性能瓶颈和IO相关。建议为日志盘(Journal和MongoDB系统日志)单独设定一个物理卷,减少对数据盘IO的资源占用。
MongoDB系统日志可以直接在命令行或者配置文件参数内指定。Journal日志不支持直接指定到另外的目录,可以通过对Journal目录创建symbol link的方式来解决。
7、禁用NUMA
非一致存储访问结构(NUMA:Non-Uniform Memory Access)是最新的内存管理技术。在一个使用NUMA技术的多处理器Linux系统上,当内存不足时,会采用SWAP的方式来获得内存,而SWAP会导致数据库性能急剧下降,所以应该禁止NUMA的使用。另外,MongoDB在NUMA环境下运行性能有时候可能会变慢,特别是在进程负载很高的情况下。