生产环境中,我们Mongo 用的是分片加集群布署,其中分片做了三个shard,每个shard又做了一主两从。大体结构如下图所示:
0.mongo写关注
cfg = rs.conf()
cfg.settings.getLastErrorDefaults = { w: "majority", wtimeout: 5000 }
rs.reconfig(cfg)
rs1:PRIMARY> cfg = rs.conf()
rs1:PRIMARY> cfg.settings.getLastErrorDefaults = { w: "majority", wtimeout: 5000 }
rs1:PRIMARY> rs.reconfig(cfg)
MongoDB支持的WriteConncern选项如下
- w: 数据写入到number个节点才向用客户端确认
- {w: 0} 对客户端的写入不需要发送任何确认,适用于性能要求高,但不关注正确性的场景
- {w: 1} 默认的writeConcern,数据写入到Primary就向客户端发送确认
- {w: “majority”} 数据写入到副本集大多数成员后向客户端发送确认,适用于对数据安全性要求比较高的场景,该选项会降低写入性能
- j: 写入操作的journal持久化后才向客户端确认
- 默认为”{j: false},如果要求Primary写入持久化了才向客户端确认,则指定该选项为true
- wtimeout: 写入超时时间,仅w的值大于1时有效。
- 当指定{w: }时,数据需要成功写入number个节点才算成功,如果写入过程中有节点故障,可能导致这个条件一直不能满足,从而一直不能向客户端发送确认结果,针对这种情况,客户端可设置wtimeout选项来指定超时时间,当写入过程持续超过该时间仍未结束,则认为写入失败。
*.读写分离设置
1.把numactl禁用(主要用来启Mongo的,因为当前服务器就一个mongo实例,所以没啥影响)
NUMA 全称 Non-Uniform Memory Access,译为“非一致性内存访问”。这种构架下,不同的内存器件和CPU核心从属不同的 Node,每个 Node 都有自己的集成内存控制器(IMC,Integrated Memory Controller)。
Numa内存分配策略有一下四种:
缺省default:总是在本地节点分配(当前进程运行的节点上)。
绑定bind:强制分配到指定节点上。
交叉interleavel:在所有节点或者指定节点上交叉分配内存。
优先preferred:在指定节点上分配,失败则在其他节点上分配。
查看当前系统numa策略:
numactl --show
因为numa默认的内存分配策略是优先在进程所在CPU的本地内存中分配,会导致CPU节点之间内存分配不均衡,
当某个CPU节点内存不足时,会导致swap产生,而不是从远程节点分配内存,这就是swap insanity现象。
Mongo是单进程多线程架构数据库,当numa采用默认内存分配策略时,Mongo进程会被并且仅仅会被分配到numa的一个节点上去。
假设这个节点的本地内存为10GB,而Mongo配置20GB内存,超出节点本地内存部分(20GB-10GB)Linux会使用swap而不是使用其他节点的物理内存。
在这种情况下,能观察到虽然系统总的可用内存还未用完,但是Mongo进程已经开始在使用swap了。
如果没有numa需要手动安装一下yum install numa
如何关闭numa呢?
(1)cat /proc/sys/vm/zone_reclaim_mode
如果上述值是0的话,说明没有开放,如果不是0,需要把值调成0.
(2)需要在/usr/lib/systemd/system/mongod.service 中启动时加上numactl启动方式,我的启动脚本加上如下所示:
ExecStart=/usr/bin/numactl --interleave=all /opt/mongodb/bin/mongod --config /data/mongo/mongodb.conf
2.禁用THP
Disable Transparent Huge Pages (THP) — MongoDB Manual
参考了上面的文档做了修改
如上所示选中never说明是禁用的
- vi /etc/init.d/disable-transparent-hugepages
- sudo chmod 755 /etc/init.d/disable-transparent-hugepages
- sudo chkconfig --add disable-transparent-hugepages
- sudo mkdir /etc/tuned/no-thp
- vi /etc/tuned/no-thp/tuned.conf
- tuned-adm profile no-thp (此命令第一次执行会报错,第二次会成功)
- Shutdown -r
- cat /sys/kernel/mm/transparent_hugepage/enabled
- cat /sys/kernel/mm/transparent_hugepage/defrag
- 或者
- cat /sys/kernel/mm/redhat_transparent_hugepage/enabled
cat /sys/kernel/mm/redhat_transparent_hugepage/defrag
3.把 vm.swappiness 的值设置成1.查了下,现在值是30.
swappiness是Linux的一个内核参数,用户控制Linux物理内存进行swap页交换的相对权重,尽量减少系统的页缓存被从内存中清除的情况。取值范围是0~100,vm.swappiness的值越低,Linux内核会尽量不进行swap交换页的操作,vm.swappiness的值越高,Linux会越多的使用swap空间。Linux系统默认值是60,当系统需要内存时,有60%的概率使用swap。对于大多数桌面系统,设置为100可以提高系统的整体性能;对于数据库应用服务器,设置为0,可以提高物理内存的使用率,进而提高数据库服务的响应性能。
Production Notes — MongoDB Manual
查看命令 cat /proc/sys/vm/swappiness
则将vm.swappiness设置为1,默认值一般是60
修改命令sysctl vm.swappiness=1
永久修改 需要修改/etc/sysctl.conf文件
增加vm.swappiness = 1
以上三步做完后,暂且未发现swap问题,如再次出现再被充
注:发现运维帮忙修改过的参数又由1变成30了,经与运维同学沟通,告知是tuned服务开启导致的,这个服务是系统性能自动调优的一个服务。查看其状态命令为: systemctl status tuned ,发现当前服务是开启状态,所以需要手动关闭一下。systemctl stop tuned,关完之后还需要把服务做disable: systemctl disable tuned
4.Ulimit参数修改:mongo 报open too many files
昨天Mongo库三个节点挂了两个,一看日志都是报了open too many files,和我司运维同学反应后,我们第一时间做了问题排查,
网上查了一下,这个错是Linux系统参数配制的问题,files不单指文件,也包括打弄的通讯连接包括socket,正在监听的端口等,也叫句柄,这个错误的原因就是进程在某个时刻打开了超过系统限制的文件数量及通讯连接数,通过命令ulimit -a 可以查看设置的最大的句柄数。mongo官网相应文档地址为:UNIX ulimit Settings — MongoDB Manual
使用命令lsof -p 进程id可以查看单个进程所有打开的文件详情,使用命令lsof -p 进程id | wc -l可以统计进程打开了多少文件,如果文件数过多使用lsof -p 进程id命令无法完全查看的话,可以使用lsof -p 进程id > openfiles.log将执行结果内容输出到日志文件中查看
修改配制文件内容如下,调整句柄数大小限制
/etc/security/limits.conf
root soft nofile 655350
root hard nofile 655350
* soft nofile 655350
* hard nofile 655350
* soft nproc 655350
* hard nproc 655350
除此外,mongo启动进程的脚本上(/usr/lib/systemd/system)也需要加上相应的配制如下所示:
# Other directives omitted
# (file size)
LimitFSIZE=infinity
# (cpu time)
LimitCPU=infinity
# (virtual memory size)
LimitAS=infinity
# (locked-in-memory size)
LimitMEMLOCK=infinity
# (open files)
LimitNOFILE=64000
# (processes/threads)
LimitNPROC=64000
5.禁止Selinux
查看Selinux是否开启:sestatus
SELinux 主要作用就是最大限度地减小系统中服务进程可访问的资源(最小权限原则)。
SELinux 有三种工作模式,分别是:
1. enforcing:强制模式。违反 SELinux 规则的行为将被阻止并记录到日志中。
2. permissive:宽容模式。违反 SELinux 规则的行为只会记录到日志中。一般为调试用。
3. disabled:关闭 SELinux。
SELinux 工作模式可以在 /etc/selinux/config 中设定。
如果想从 disabled 切换到 enforcing 或者 permissive 的话,需要重启系统。反过来也一样。
enforcing 和 permissive 模式可以通过 setenforce 1|0 命令快速切换。
(6)排查问题iostat -mxt 1
Mongo报IO问题
现象,Mongo的主片副本集在运行一段时间后,dirty会高于20%,无法刷盘,flush也不在是60s持行一次。服务器内存是64G,并未配制wireTriger的cachSize,走的是默认(RAM-1)*0.5,但实际上res可达到37G左右,然后会发现有大量的写入请求(非正常业务量的写请求)进来,咨询了DBA,据说是因为一直不刷盘,所以脏页数据积累,看到的大量写请求应该是积累的写操作。iostat -mxt 1命令查看系统IO资源使用情况,可见util 100%比较多,接下来的调整就是想办法让脏页数据刷盘。在优化过程中,我们首先需要理解以下配制信息:
mongodb默认存储因为wiredtiger的cache淘汰策略相关的几个配置如下:
了解了以上的wiredtiger cache策略后,我们的IO优化思想主要是让后台evict尽量早点淘汰脏页page到磁盘,同时调整evict淘汰线程数来加快脏数据淘汰,主要分了以下三步走:
(1)显示设置WireTriger的cacheSize大小
因为默认的设置感觉未生效,所以DBA建议显示设置,这样脏页刷盘的数据量可以保证在dirty%*res,以控制磁盘的写入量。我们设定了32G.在Mongo的配制文件中设置,修改后需要重启Mongo实例生效。如下所示:
(2)增加淘汰线程数量
如下图所示:淘汰脏页的线程数量默认最小是1,最大是8,适当地增加些线程个数,可以提高脏数据的淘汰率,保证热数据(res中的data+index)的产生率与脏页淘汰率保持一个相对稳定状态,不至于res过高,dirty过高,如果rds过高,dirty过高说明热数据产生率要高于脏页淘汰率,当这两值乘积变大时,对IO写入也是有些影响的。但设定的线程数量也要根据机器的实际配制做调整,不然会导至CPU升高。
线程调整的命令如下所示:
db.adminCommand({setParameter: 1, wiredTigerEngineRuntimeConfig: "eviction=(threads_min=4,threads_max=12)"})
此命令执行完可以不需要重启即可生效。
(3)优化checkPoint频度
checkPoint检查点可理解成是快照的写入,正常情况下默认是60s写入一次的,除了默认时间外,还有一个journal日志达到2G也会触发checkPoint频度,说到这了,给大家一个大神的MongoIO性能调整的贴子连接,做为参考OPPO百万级高并发MongoDB集群性能数十倍提升优化实践 | MongoDB中文社区
优化的步䯅可以参考下图:
设置命令:
shard-b:SECONDARY> db.adminCommand({setParameter: 1, wiredTigerEngineRuntimeConfig: "checkpoint=(log_size=1G,wait=40)"})
查看命令:
shard-b:SECONDARY> db.adminCommand({getParameter: 1, wiredTigerEngineRuntimeConfig: 1})
附:
查询命令
(1)shard-b:SECONDARY> db.serverStatus().wiredTiger
可以看到关于wireTigger的很多详细信息,其中通过cache也可以看到当前活跃的线程数用到多少,如下图所示:
(2)shard-b:SECONDARY> rs.printReplicationInfo()
通过这个命令可以查看OpLog的数据追赶时间等 的情况
呃,先去吃饭了,有空再写