记一次mongo服务端无法建立更多连接造成的客户端无法访问mongo集群的故障分析及解决
一. 问题:
程序无法连接mongo集群
现象:
2017-09-05T01:29:08.765+0000 I NETWORK [thread2] connection refused because too many open connections: 819
二. 排查及解决
1. 本地测试访问mongo主机及端口
telnet 192.168.1.100 20000
正常访问,端口存在
2. 登陆mongo主机查看进程和端口是否存在。
查看进程
ps -ef | grep mongo
查看端口
netstat -ntlp
确认进程和端口都正常运行
3. 查看日志
tail -f /data/mongodb/log/mongos.log
从log文件中可以看出connection refused because too many open connections: 819,不能建立更多的连接造成,mongo服务端主动拒绝,造成客户端无法访问。于是想到系统允许进程打开的的最大文件具柄数的限制。
三. 分析解决
1. 查看系统默认的最大文件句柄数,系统默认是1024
# ulimit -n 1024参数:命令参数-a 显示所有限制-c core文件大小的上限-d 进程数据段大小的上限-f shell所能创建的文件大小的上限-m 驻留内存大小的上限-s 堆栈大小的上限-t 每秒可占用的CPU时间上限-p 管道大小-n 打开文件数的上限-u 进程数的上限-v 虚拟内存的上限
2. 查看当前进程打开了多少句柄数
# lsof -n|awk ‘{print $2}‘|sort|uniq -c|sort -nr|more 14505 2684 13937 2781 12992 2492 11616 2361 10486 2583 #其中第一列是打开的句柄数,第二列是进程ID。
根据进程PID查看进程名
# ps -ef | grep 2684 mongodb 2684 1 0 04:19 ? 00:00:38 mongod -f /data/mongodb/config/shard2.conf
3. 什么是ulimit -n
网上很多人说,ulimit -n限制用户单个进程的问价打开最大数量。严格来说,这个说法其实是错误的。看看ulimit官方描述:
Provides control over the resources available to the shell and to processes started by it, on systems that allow such control. The -H and -S options specify that the hard or soft limit is set for the given resource. A hard limit cannot be increased once it is set; a soft limit may be increased up to the value of the hard limit. If neither -H nor -S is specified, both the soft and hard limits are set. The value of limit can be a number in the unit specified for the resource or one of the special values hard, soft, or unlimited, which stand for the current hard limit, the current soft limit, and no limit, respectively.If limit is omitted, the current value of the soft limit of the resource is printed, unless the -H option is given. When more than one resource is specified, the limit name and unit are printed before the value.
人家从来就没说过是限制用户的单个进程的最大文件打开数量,看看红色部分,是限制当前shell以及该shell启动的进程打开的文件数量。为什么会给人限制单个线程的最大文件数量的错觉,因为很多情况下,在一个shell环境里,虽然可能会有多个进程,但是非常耗费文件句柄的进程不会很多,只是其中某个进程非常耗费文件句柄,比如服务器上运行着一个tomcat,那么就是java进程要占用大多数文件句柄。此时ulimit设置的最大文件数和java进程耗费的最大文件数基本是对应的,所以会给人这样的一个错觉。
还有,很多文章称ulimit -n 只允许设置得越来越小,比如先执行了ulimit -n 1000,在执行ulimit -n 1001,就会报"cannot modify limit: Operation not permitted"错误。这个其实也是不准确的说法。首先要搞清楚,任何用户都可以执行ulimit,但root用户和非root用户是非常不一样的。
注: 非root用户只能越设置越小,不能越设置越大,root用户不受限制
4. 到底最大文件数被什么限制了?too many open files错误到底可以通过什么参数控制?
shell级限制
通过ulimit -n修改,如执行命令ulimit -n 1000, 当前session会话生效,则表示将当前shell的当前用户所有进程能打开的最大文件数量设置为1000.
用户级限制
ulimit -n是设置当前shell的当前用户所有进程能打开的最大文件数量,但是一个用户可能会同时通过多个shell连接到系统,所以还有一个针对用户的限制,通过修改 /etc/security/limits.conf实现,例如,往limits.conf输入以下内容:
root soft nofile 1000
root hard nofile 1200
soft nofile表示软限制,hard nofile表示硬限制,软限制要小于等于硬限制。上面两行语句表示,root用户的软限制为1000,硬限制为1200,即表示root用户能打开的最大文件数量为1000,不管它开启多少个shell。
系统级限制
# cat /proc/sys/fs/file-max 1637385
ulimit修改后生效周期
修改后立即生效,重新登录进来后失效,因为被重置为limits.conf里的设定值。
修改了limits.conf需要重启系统?
重新登录进来就生效了。
5. 文件/proc/sys/fs/file-max
网上说,ulimit -n 和limits.conf里最大文件数设定不能超过/proc/sys/fs/file-max的值,这也是搞笑了,/proc/sys/fs/file-max是系统给出的建议值,系统会计算资源给出一个和合理值,一般跟内存有关系,内存越大,改值越大,但是仅仅是一个建议值,limits.conf的设定完全可以超过/proc/sys/fs/file-max。
6. 修改limit限制
# 在文件末尾添加,永久生效 # vim /etc/security/limits.conf mongodb soft nofile 100000 mongodb hard nofile 100000 # 切换到mongodb用户下查看 # ulimit -n 100000
重启mongo后,故障恢复!
四. 总结
- /proc/sys/fs/file-max限制不了/etc/security/limits.conf
- 只有root用户才有权限修改/etc/security/limits.conf
- 对于非root用户, /etc/security/limits.conf会限制ulimit -n,但是限制不了root用户
- 对于非root用户,ulimit -n只能越设置越小,root用户则无限制
- 任何用户对ulimit -n的修改只在当前环境有效,退出后失效,重新登录新来后,ulimit -n由limits.conf决定
- 如果limits.conf没有做设定,则默认值是1024
- 当前环境的用户所有进程能打开的最大文件数量由ulimit -n决定