問題發現
先上圖,從容器監控裏面看到cpu已經長期保持100%運行。(藍色線條cpu,綠色的是內存)
排查過程
通過堡壘機連上服務器查jstack
1、由於這臺容器裏面就一個java服務,而且已經確定是這個服務的問題,因此直接jps查詢對應pid(如果無法確定應用範圍需要用top命令排序查看最耗費cpu資源的進程pid)
2、使用top -H -p 228命令查看該應用進程下佔用cpu資源最高的線程,結果如下圖。其中%CPU越高的表示耗費cpu資源越高,TIME列表示cpu持續執行時間(可以看到這幾個好非資源大的線程都執行了150分鐘,210分鐘以上,明顯是有問題的)
3、先使用jstack 命令把這個佔用最高cpu的進程堆棧信息輸出到文件“localadmin.txt”中,方便後續查看。
jstack 228 >> localadmin.txt
4、通過線程pid查找具體堆棧信息。從第2步可以看到,佔用cpu資源最高的幾個線程是 35465、246527、253809等……這裏需要注意的是jstack文件中是按照16進制標示堆棧信息的,因此這裏需要先把35465等信息轉換爲16進制,即0x8A89,然後在上面導出的localadmin.txt文件中找到對應的堆棧信息。可以看到範圍鎖定在RPCProxyFactoryBeanRPCProxyFactoryBean的invoke方法,這個方法在我項目中是執行動態代理遠程調用客戶端方法並接受信息的。
在接受消息處理時採用的方式是如下代碼,這個result在正常場景下沒有問題,但是在tcp超時,或者業務超時後會一直處於循環中。問題找到,解決方法有兩種一種是通過GenericFutureListener接口異步執行操作結束後的回調,一種是我當前的解決方法,接受消息繼續用 f.channel().closeFuture().sync(); ,在後續分發器finally中監聽ChannelFutureListener.CLOSE
do { // 接收返回信息 result = ClientChannelUtil.getResult(uuid); LOGGER.debug("接受返回消息,uuid:【{}】,result:【{}】",uuid,result); } while (result == null);
修復後重新上線,觀察,問題解決。