# 問題描述
公司做的是一個支付系統,會對接很多第三方公司。
突然有一天,有一家第三方(簡稱金花平台)反應收不到我們的通知消息。
# 排查過程
我們登陸自己的服務器,檢查程序日志,是有給金花平台發送通知的。而且大多訂單都是通知成功而且金花平台也成功返回了。
仔細檢查日志后,發現金花平台說的沒有收到通知的訂單其實在我們服務器的日志里面是有發送的,只是沒有返回
與金花平台溝通后,手動模擬程序給金花平台發送通知后,金花平台反饋之前沒有收到通知的訂單經過手動模擬發送通知成功了
# 定位問題
與研發溝通后,緊急更新加了一些通知模塊更加詳細的日志{具體是一些內部交互以及通知第三方時候的每一步日志}
等遇到新的問題訂單后,發現加的那些日志也定位不到具體的問題。
和公司負責研發的負責人商量后,決定從頭開始檢查一遍{包括服務器的資源,服務自身的線程池}
等檢查到服務自身線程池的時候發現 負責通知的模塊有死鎖的線程池,釋放不了
下面標紅是獲取到的線程池其中的一個帶鎖的,可以看出卡在了dns解析,所以造成了死鎖
"Thread-2199" #2595 prio=5 os_prio=0 tid=0x00007f20fc0a5800 nid=0x10b0d in Object.wait() [0x00007f20a940d000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) at java.lang.Object.wait(Object.java:502) at java.net.InetAddress.checkLookupTable(InetAddress.java:1393) - locked <0x00000000804a4e78> (a java.util.HashMap) at java.net.InetAddress.getAddressesFromNameService(InetAddress.java:1310) at java.net.InetAddress.getAllByName0(InetAddress.java:1276) at java.net.InetAddress.getAllByName(InetAddress.java:1192) at java.net.InetAddress.getAllByName(InetAddress.java:1126) at org.apache.http.impl.conn.SystemDefaultDnsResolver.resolve(SystemDefaultDnsResolver.java:45) at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:112) at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:373) at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:381) at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:237) at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185) at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89) at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:111) at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108) at vip.dcpay.util.http.HttpHelper.execute(HttpHelper.java:246) at vip.dcpay.util.http.HttpHelper.post(HttpHelper.java:113) at vip.dcpay.order.notify.domain.util.CallbackInterfaceUtil.callbackNotify(CallbackInterfaceUtil.java:84) at vip.dcpay.order.notify.domain.service.TaskRetryService.notify(TaskRetryService.java:85) at vip.dcpay.order.notify.domain.service.TaskRetryService$$FastClassBySpringCGLIB$$3b7fcca6.invoke(<generated>) at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:747) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.retry.interceptor.RetryOperationsInterceptor$1.doWithRetry(RetryOperationsInterceptor.java:91) at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:287) at org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:180) at org.springframework.retry.interceptor.RetryOperationsInterceptor.invoke(RetryOperationsInterceptor.java:115) at org.springframework.retry.annotation.AnnotationAwareRetryOperationsInterceptor.invoke(AnnotationAwareRetryOperationsInterceptor.java:153) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689) at vip.dcpay.order.notify.domain.service.TaskRetryService$$EnhancerBySpringCGLIB$$f6eef3da.notify(<generated>) at vip.dcpay.order.notify.domain.service.CallBackReceiveService$1.run(CallBackReceiveService.java:56) at java.lang.Thread.run(Thread.java:748)
# 具體查看死鎖線程池的方法:
ps -ef|grep 項目名稱 # 找到對應項目的進程號 jstack 進程號 # 實時獲取正在運行的線程池
# 問題處理方案
vim /etc/resolv.conf # 編輯文件,添加如下信息。問題得到解決
options timeout:2 attempts:1 rotate #dns解析超時時間設置為2秒,從第一個namesever開始輪詢 nameserver 9.9.9.9 nameserver 1.1.1.1 nameserver 8.8.8.8
參數說明:
timeout:dns解析超時時間,默認是5秒。筆者在生產環境中實際配置的是2秒
attempts:從第幾個nameserver開始dns解析輪詢