编辑推荐: |
本节主要介绍
了性能优化分类、 软件层面优化、系统层面优化等方面内容。
本文来自博客园,由火龙果软件Anna编辑、推荐。 |
|
1. 性能优化分类
mongodb性能优化分为软件层面和操作系统层面。
软件层面,一般通过修改mongodb软件配置参数来达到,这个需要非常熟悉mongodb里面的各种配置参数;
而操作系统层面,相对简单点,主要是修改操作系统参数,比如说:关闭传输页缓存、使用SSD替代机器硬盘等等。
2. 软件层面优化
2.1 设置WiredTiger的cacheSizeGB
通过cacheSizeGB选项配置控制WiredTiger引擎使用内存的上限,默认配置在系统可用内存的60%左右。
如果一台机器上只部署一个mongod,mongod可以使用所有可用内存,则使用默认配置即可。
如果一台机器上部署多个mongod,或者mongod跟其他的一些进程一起部署,则需要根据分给mongod的内存配额来配置cacheSizeGB,按配额的60%左右配置即可。
通过配置文件配置cacheSizeGB,如下:
2.2 分配足够的Oplog空间
Oplog是MongoDB local库下的一个固定集合,Secondary就是通过查看Primary
的oplog这个集合来进行复制的。Oplog可以说是MongoDB Replication的纽带。Oplog是固定大小的,它只能保存特定数量的操作日志。如果oplog
size过大,会浪费存储空间;如果oplog size过小,老的oplog记录很快就会被覆盖,那么宕机的节点很容易出现无法同步数据的现象,因此设置合理的oplog大小对mongodb很重要。MongoDB默认将其大小设置为可用disk空间的5%(默认最小为1G,最大为50G)。
这里设置oplog为10000MB,如:
2.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格式显示时间戳
2.4 设置journal日志刷新时间和flush时间
commitIntervalMs:mongod的journal日志刷新值范围从1到500毫秒。较低的值增加了journal的耐久性,以牺牲性能为代价,在WiredTiger引擎上,默认的日志提交间隔为100毫秒,增大commitIntervalMs可以降低磁盘的IO压力,起到一定的优化作用。不过一般情况下,不建议修改。
syncPeriodSecs:mongod使用fsync操作将数据flush到磁盘的时间间隔,默认值为60(单位:秒),增大该值也可以降低磁盘IO压力,起到一定优化作用。一般情况下,强烈建议不要修改此值。mongod将变更的数据写入journal后再写入内存,并间歇性的将内存数据flush到磁盘中,即延迟写入磁盘,有效提升磁盘效率。此指令不影响journal存储,仅对mongod有效。
3. 系统层面优化
3.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,然后保存并source
/etc/profile
3.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添加如下设置:
* soft nofile
1048576
* hard nofile 1048576
* soft nproc 524288
* hard nproc 524288 |
3.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,添加如下设置:
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 |
3.4 使用XFS文件系统,同时禁掉数据库文件的atime
MongoDB在WiredTiger存储引擎下建议使用XFS文件系统。Ext4最为常见,但是由于ext文件系统的内部journal和WiredTiger有所冲突,所以在IO压力较大情况下表现不佳。
在使用XFS文件系统的同时,我们建议在文件系统的mount参数上加上noatime,nodiratime两个选项。用noatime
mount的话,文件系统在程序访问对应的文件或者文件夹时,不会更行对应的access time。
一般来说,Linux会给文件记录三个时间,change time,modify time 和 access
time。我们可以通过stat来查看文件的三个时间。其中access time指文件最后一次被读取的时间,modify
time指的是文件的文本内容最后发生变化的时间,change time指的是文件的inode最后发生变化(比如位置、用户属性、组属性等)的时间。
一般来说,文件都是读多写少的,而且我们也很少关心某一文件最近什么时间被访问了,所以,我们建议采用noatime选项,这样文件系统不记录access
time,避免浪费资源。禁止系统对文件的访问时间更新会有效提高文件读取的性能。
操作如下:
1) Centos7的安装xfsprogs-4.5.0-15.el7.x86_64.rpm包,而Centos6的安装xfsprogs-3.1.1-20.el6.x86_64.rpm。
rpm -ivh xfsprogs- 3.1.1 -20.el6.x86_64.rpm
2) 格式化为XFS文件系统,有两种情况,一是把已存在的Ext4等文件系统格式化为XFS文件系统,二是把尚未格式化的磁盘格式化为XFS文件系统。
一、把已存在的Ext4格式化为XFS文件系统,以/opt目录为例,我们把/opt作为mongodb的安装及存储目录:
① 首先使用命令 lsblk -f 查看磁盘分区及其对应的目录
② 然后 umount /opt 把/opt目录卸载掉
③ 使用 mkfs.xfs -f /dev/sda5 把ext4文件系统覆盖为xfs文件系统,并使用lsblk
-f查看是否修改成功
④ 接着修改/etc/fstab文件,让系统开机自动挂载该磁盘分区为/opt,在/etc/fstab文件里,把/opt对应那行的ext4改为xfs,并在defaults后面加上“,noatime”,把atime禁掉
⑤ 最后,把/opt挂载上,并禁掉atime,并用 lsblk -f 查看
二、把尚未格式化的磁盘格式化为XFS文件系统
① 首先使用命令 fdisk -l 查看空闲的磁盘分区
从上图可以看出磁盘/dev/sda总大小为42.9GB,/dev/mapper/centos-root占用29GB,而/dev/mapper/centos-swap占用2GB,故空余尚未格式化的磁盘大约占10GB;磁盘/dev/sda占用83886080个sectors,而目前/dev/sda2使用到的sectors为62914559,还剩余20971521个sectors尚未使用,这也是看出尚未格式化的磁盘的方法;
② 创建新的磁盘分区
③ 执行partprobe或者重启
执行 partprobe 命令用于将磁盘分区表变化信息通知内核,并请求操作系统重新加载分区表,可以避免必须重新启动的问题
执行 partprobe 命令之前,使用 lsblk -f 来查看磁盘分区,没有看到/dev/sda3;执行
partprobe 命令后,再次使用 lsblk -f 查看磁盘分区
后面的操作同方式一的④⑤操作,挂载并禁掉atime,最后在/etc/fstab上面添加/dev/sda3及其对应挂载的路径
3.5 使用SSD或RAID10来提供存储IOPS能力
MongoDB是一个高性能高并发的数据库,其大部分的IO操作为随机更新。一般来说本机自带的SSD是最佳的存储方案。如果使用普通的磁盘,建议使用RAID10条带化来提供IO通道的并发能力。
注意:
IOPS (Input/Ouput Operations Per Second):是存储设备每秒读写的次数。
RAID10:RAID1 + RAID0的结合,RAID1是一个冗余的备份阵列,RAID0是负责数据的读写阵列。例如:磁盘1和磁盘2组成一个Raid1,磁盘3和磁盘4又组成另外一个Raid1;这两个Raid1组成了一个新的Raid0。其中磁盘1和磁盘2的数据是相互备份的,磁盘3和磁盘4的数据是相互备份的。
3.6 为Data和Journal/log分别使用单独的物理卷
MongoDB很多的性能瓶颈和IO相关。建议为日志盘(Journal和MongoDB系统日志)单独设定一个物理卷,减少对数据盘IO的资源占用。
MongoDB系统日志可以直接在命令行或者配置文件参数内指定。Journal日志不支持直接指定到另外的目录,可以通过对Journal目录创建symbol
link的方式来解决。
如,/resource目录和 /opt目录分别是两个不同的物理磁盘,
data存储数据设置在 /resource 目录,通过如下配置参数设置
Journal和log数据设置在 /opt 目录,通过如下配置参数设置
Journal日志是MongoDB的预读写日志,用于数据库崩溃时的数据恢复,可以在配置文件配置参数禁掉,通常生产环境不建议禁掉。Journal一般是在data存储目录下,通过创建软连接symbol
link来把路径引到/opt目录下
ln -s /resource/mongodbCluster/shard1/data/journal
/opt/mongodbCluster/shard1/journal
3.7 禁用NUMA
非一致存储访问结构(NUMA:Non-Uniform Memory Access)是最新的内存管理技术。在一个使用NUMA技术的多处理器Linux系统上,当内存不足时,会采用SWAP的方式来获得内存,而SWAP会导致数据库性能急剧下降,所以应该禁止NUMA的使用。另外,MongoDB在NUMA环境下运行性能有时候可能会变慢,特别是在进程负载很高的情况下。
禁用NUMA的方法,在mongod前面加“numactl --interleave=all”:
numactl --interleave=all /opt/app/mongodb/bin/mongod
-f /opt/app/mongodbCluster/conf/config.conf
3.8 设置vm.swappiness
vm.swappiness是操作系统控制物理内存交换出去的策略。它允许的值是一个百分比的值,最小为0,最大为100,该值默认为60.
vm.swappiness设置为0表示尽量少swap,100表示尽量将inactive的内存页交换出去。
具体的说,当内存基本用满的时候,系统会根据这个参数来判断是把内存中很少用到的inactive内存交换出去,还是释放数据的cache。cache中缓存着从磁盘读出来的数据,根据程序的局部性原理,这些数据有可能在接下来又要被读取;inactive内存顾名思义,就是那些被应用程序映射着,但是“长时间”不用的内存。
我们可以利用vmstat看到inactive的内存数量,也可以通过 /proc/meminfo 看到更详细的信息:
MonogDB本身也是一个内存使用量较大的数据库,它占用的内存比较多,不经常访问的内存也会不少,这些内存如果被linux错误的交换出去了,将浪费很多CPU和IO资源,极大地降低数据库的性能。如果vm.swappiness设置为0,会带来内存溢出的问题,当内存不足时,会强制把某些程序kill掉。所以最好在MongoDB的服务器上设置vm.swappiness的值在1~10之间,尽可能少地使用swap。如果服务器内存比较大时,可以考虑设置vm.swappiness=0。
3.9 修改磁盘调度算法
对于磁盘I/O,Linux提供了Completely Fair Queuing(CFQ),Deadline
scheduler和NOOP三种调度策略
目前Linux默认调度策略是CFQ,它声称对每一个IO请求都是公平的,这种调度策略对大部分应用都是适用的。但是如果数据库有两个请求,一个请求3次IO,一个请求10000次IO,由于绝对公平,3次IO的请求需要跟10000次IO的请求竞争,可能要等待上千个IO完成才能返回,导致它的响应时间非常慢。并且如果在处理的过程中,又有很多IO请求陆续发送过来,部分IO请求甚至可能一直无法得到调度被“饿死”。而Deadline
scheduler调度策略则可以兼顾到一个请求不会在队列中等待太久导致饿死,对数据库这种应用来说更加适用。
暂时性设置,会失效:
echo deadline > /sys/block/sda/queue/scheduler
永久性设置,对于Centos6来说,在/etc/grub.conf的kernel行最后添加elevator=deadline来永久生效:
对于Centos7来说,执行如下命令:
grubby --update-kernel=ALL --args="elevator=deadline"
然后重启生效。
注意:
一般Centos7默认支持的是deadline算法,而Centos6默认支持的cfq,而一般我们会在SSD硬盘环境中使用noop算法。
3.10 预读值(readahead)设置
预读值是文件操作系统的一个优化手段。Linux预读默认256个扇区,大小为128K。MongoDB很多都是随机访问,对于随机访问,预读值readhead应该设置较小为好。采用Linux的blockdev命令来把预读readhead设置小一点,可以减少内存中无用数据占用,从而优化IO性能。RA代表预读大小(扇区),推荐数值是16到32,如文档较小,预读数值可以小一点,修改后MongoDB重启才能生效。
可以使用下述命令来显示当前系统的预读值:
暂时性更改预读值,执行命令 blockdev --setra 32 /dev/sdb ,/dev/sdb为mongodb存储的磁盘设备:
永久性更改,将 blockdev --setra 32 /dev/sdb 写入配置文件/etc/rc.local,否则重启就会失效:
3.11 设置Linux内核参数
打开/etc/sysctl.conf,在里面添加如下内容:
#并发连接backlog设置
net.core.somaxconn=32768
net.core.netdev_max_backlog=16384
net.core.rmem_default=262144
net.core.wmem_default=262144
net.core.rmem_max=16777216
net.core.wmem_max=16777216
net.core.optmem_max=16777216
#可用知名端口范围:
net.ipv4.ip_local_port_range ='1024 65535'
net.ipv4.tcp_max_syn_backlog =16384
#TCP Socket 读写 Buffer 设置:
net.ipv4.tcp_rmem= '1024 4096 16777216'
net.ipv4.tcp_wmem= '1024 4096 16777216' |
添加完之后,不重启更新:sysctl -p
|