一次MongoDB的Socket Exception

今天重新部署了一个项目,该项目启动的时候会访问MongoDB获取一些数据,一个蛮简单的项目,从前发布都没问题,这次启动的时候直接就是Socekt Exception:

nested exception is org.springframework.data.mongodb.UncategorizedMongoDbException: socket exception [SEND_ERROR] for x.x.x.x:xx; nested exception is com.mongodb.MongoException: socket exception [SEND_ERROR] for x.x.x.x:xx

第一反应是内网网络不太好,网络波动嘛,经查有的事儿。

解决办法:多试几次……

很明显,这个办法没解决问题(这要是解决了就不会在这儿写这个了)。同时ping mong实例所在的主机,0.3ms之内就返回了,也没有丢包。

然后去mongo那边看了看,也没啥问题,运行的很正常,log里也没什么错误。 而且Mongo这边配置的最大连接数是2W,这连接现在才用了不到9000啊。

这事情就比较奇怪了,以前从来没遇到,既然是Socekt Exception只能继续忘网络方向想了。

首先查看一下tcp连接中各个状态的连接数:

admin@linux:~> netstat -an | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
TIME_WAIT 3615
CLOSE_WAIT 130
FIN_WAIT1 11
FIN_WAIT2 69
ESTABLISHED 1983
SYN_RECV 7
CLOSING 23
LAST_ACK 39
LISTEN 30

这个命令呢,我也是搜来的,上面显示的是一台服务运行正常的机器上面的结果,而出问题那台呢,ESTABLISHED有6000多,这明显不科学呀,就业务层面来看,它的压力应该更小点才对。

这得看一下这多出来的连接是和哪台机器建立的,继续:

netstat -an |grep ESTA |awk '{print$5 "\n"}' |awk 'BEGIN {FS=":"} {COUNT[$1]++}END{for(a in COUNT) print a, COUNT[a]}' |sort -k 2 -nr

打印出来所有和该机器建立连接的IP以及连接数,一看果不其然是跟mongo所在的机器建立的连接超多,占到了ESTABLISHED连接的绝大部分。

这得看一下是哪个进程出的问题,继续:

netstat -anp |grep ESTA |awk '{print$7 }' |awk ' {COUNT[$1]++}END{for(a in COUNT) print a, COUNT[a]}' |sort -k 2 -nr

这样看一下到底哪些进程占用的ESTABLISHED连接多,拿到进程号之后,很容易找到对应的服务,结果呢另外一个服务占用了很多ESTABLISHED连接。

netstat -anp | grep {pid}| grep ESTA |awk '{print$5 "\n"}' |awk 'BEGIN {FS=":"} {COUNT[$1]++}END{for(a in COUNT) print a, COUNT[a] }'

跟据pid反过来可以查看此进程和哪些机器建立了连接,以及建立了多少连接。

这个服务居然占用了5000个mongo连接,太夸张了!!大概就是它把连接占完了,这就是罪魁祸首了!

等等,我们的mongo不是最大有2w个连接吗?就算这个出奇的占了这么多也不至于让别的起不来呀!先把5000这个错误修正让服务跑起来再说,检查了一下,这是配置上的问题,connections-per-host这个参数配置成了500,改成一个合理的值比如100,所有都恢复正常了,原先的服务也能起来了。

接下来分析两个问题:

  1. connections-per-host这个参数是什么意思
  2. mongo的最大连接数怎么没生效

先说第二个,这个比较简单。

主要原因在于,即使mongo的配置里面最大连接数是2w,系统里面每个进程的最大打开文件数(open files)只有65535,所以mongo的最大连接数其实也只有65535。连接数有问题的那个服务占掉了5000个,剩下的被其他服务占用了,所以重新部署的那个服务无法再获得新的连接了。

这个地方唯一比较让人郁闷的是mongo这边log里也没报错……

再说第一个问题。官方API中对这个参数的解释是这样的:The maximum number of connections allowed per host for this Mongo instance.。允许每个host对这个Mongo实例创建的最大连接数。 根据使用的情况,个人反倒觉得解释为允许每个process对这个Mongo实例创建的最大连接数更合适一些。如果是允许每个机器创建的最大连接数,那么同一台机器上不管部署多少个服务连接到这个Mongo上面,这个机器和Mongo之间的最大连接数都应该是设置的这个值,可实际情况并不是这样。

另外,也没发现Mongo连接池有回收的机制,依据个人使用经验,连接数目基本上只增不减(即使在不需要这么连接的时候),最多增至设置的connections-per-host

上面这些分析是个人的一个见解,可能不准确,欢迎指正。

你可能感兴趣的:(一次MongoDB的Socket Exception)