系統環境
netty:netty3.2.4
linux:CentOS Linux release 7.1.1503
motan:開源版1.1.1
一、問題現象
1、訪問服務連接不上,服務拒絕連接。流量突降觸發報警。
2、有大量Too many files報錯
3、認證服務返回403
4、NettyClient request Error 報錯 分爲
a、 java.lang.IllegalStateException: await*() in I/O thread causes a dead lock or sudden performance drop. Use addListener() instead or call await*() from a different thread.
b、 com.weibo.api.motan.exception.MotanServiceException: error_message: NettyChannel failed to connect to server, url: motan://10.22.6.156:8881/cn.sina.api.user.service.SinaUserMappingService, status: 503, error_code: 10001,r=0
1、根據1和2,得知現在我自己的業務系統(代理服務)的連接已經被打滿。無法接收服務 access log已經沒有流量進來了。
(lsof -p [pid] | wc -l 驗證連接達到20w+,顯示被TCP連接ESTABLISHED狀態佔滿) tcp泄露問題
2、查看tcp的連接都是哪些資源,發現是用戶關係方面的。
3、根據3、4a、4b 得知 是通過motan調用rpc服務導致tcp泄露。
先把結論放上來,帶着結果看更清楚點
1、 不要在一個netty的I/O worker線程中開啓中再次再次開啓一個NettyChannel(nettty worker線程中再次使用netty千萬要注意---netty4、5修改了具體原因請看下一篇解決方案) 如果worker中一定要再次使用,那就要自己新開線程來搞定了。
2、 motan是否可以在檢查死鎖觸發後,關閉NettyChannel連接。(導致tcp連接泄露)
二、問題總結, netty的I/O work線程 通過motan調用接口 導致netty的死鎖檢查報錯。
報錯後其實創建channl是創建成功了 但是沒有關閉channl連接並且無法複用
導致每次請求都會新建連接,tcp連接泄露打滿docker中的連接數量 拋出too many files。
三、接下來就是尋找爲什麼會觸發netty的死鎖檢查。
報錯的棧信息
從錯誤棧看在什麼時候觸發的檢查,尋找到以下代碼 此處爲motan源碼,可以看到1處報錯不能觸發2關閉連接
觸發死鎖檢查的代碼,下面我們去看下實現。
經過分析isUseDeadLockChecker() 默認是true , 那麼就是PARENT(一個ThreadLocal)搞得鬼。繼續找在哪對PARENT操作了
就是在這裏,會發現是開啓I/O worker線程線程的時候塞入了PARENT, 並且死鎖檢查並不關心這裏面是什麼只要不爲空就會拋出死鎖風險異常
可以發現,是我本身的代理服務中啓動了一個I/O worker線程,並且在這個線程中 調用motan open了一個NettyChannel時觸發了checkDeadLock並且發現有死鎖風險(PARENT不爲空)
四、爲什麼PARENT不爲空呢?
通過觀察錯誤線程棧(圖二)發現, motan open NettyChannel是時候是在我們本身netty工程的work線程中做的。
這樣導致自身在open NettyChannel的時候在PARENT中放入值。 後來的motan open NettyChannel 時checkDeadLock發現有死鎖危險,拋出異常。
五、問題總結
拋出的死鎖檢查異常導致我們沒有做cancel(); 使得tcp連接連接佔用滿
六、結論
1、 不要在一個netty的I/O worker線程中開啓中再次再次開啓一個NettyChannel(nettty worker線程中再次使用netty千萬要注意---netty4、5修改了具體原因請看下一篇解決方案) 如果worker中一定要再次使用,那就要自己新開線程來搞定了。
2、 motan是否可以在檢查死鎖觸發後,關閉NettyChannel連接。(導致tcp連接泄露)
3、請期待下一篇, 定位後的解決方案。