今天重新部署了一個項目,該項目啟動的時候會訪問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 3615CLOSE_WAIT 130FIN_WAIT1 11FIN_WAIT2 69ESTABLISHED 1983SYN_RECV 7CLOSING 23LAST_ACK 39LISTEN 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,所有都恢複正常了,原先的服務也能起來了。
接下來分析兩個問題: connections-per-host這個參數是什麼意思 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。
上面這些分析是個人的一個見解,可能不準確,歡迎指正。