地方政府網(wǎng)站建設(shè)中存在的問題怎么在百度上發(fā)布廣告
背景
最近線上的日志全局追蹤 traceId 不好使了,不同請(qǐng)求經(jīng)常出現(xiàn)重復(fù)的 traceId,或者通過某個(gè)請(qǐng)求的 traceId 追蹤搜索,檢索出了與該請(qǐng)求完全不相干的日志。我領(lǐng)導(dǎo)叫我去排查解決這個(gè)問題,這里我把我排查的過程思路以及如何解決這個(gè)問題稍微記錄下。
全鏈路追蹤原理:Spring web 的攔截器(HandlerInterceptor)+ 阿里的一個(gè)開源工具 (TransmittableThreadLocal 支持主線程到線程池的透?jìng)?#xff09;+ feign 的 RequestInterceptor
排查過程
在排查日志之前,我經(jīng)驗(yàn)告訴我,這大概率是 TTL 的 agent 代理與線上的 arm 監(jiān)控代理沖突,導(dǎo)致線程池透?jìng)?traceId 沒生效導(dǎo)致的(我以前也碰到過這類問題)
- 查看每個(gè)前端請(qǐng)求接口的日志打印,發(fā)現(xiàn)不同的請(qǐng)求確實(shí)存在重復(fù)的 traceId。
接著,我去看了下打印這行日志的實(shí)現(xiàn),如下圖,是通過一個(gè) AOP 切面攔截所有的rest 請(qǐng)求去打印。其中,打印日志使用了線程池。
結(jié)論一:證實(shí)了我的猜測(cè),線程池透?jìng)?traceId 沒生效。也就是說,所有接口業(yè)務(wù)中使用到線程池的都可能會(huì)串 traceId。
-
當(dāng)時(shí)我以為這就完了。在一次偶然的排查線上問題中發(fā)現(xiàn),基本在同一時(shí)間,沒有使用到線程池的兩個(gè)業(yè)務(wù)接口,打印的日志的 traceId 是一樣的。
我首先想到是,是不是接口請(qǐng)求接口沒清除 traceId 呢,也就是沒有重寫 攔截器的 org.springframework.web.servlet.handler.HandlerInterceptorAdapter#afterCompletion 方法呢?
我去看一了下源代碼,雖然沒有重寫afterCompletion() 方法在每次請(qǐng)求結(jié)束之后清除 traceId,但看 如上的preHandle()方法的代碼邏輯,不清除也不要緊,如上代碼所示,當(dāng)在請(qǐng)求頭中獲取 traceId 不存在時(shí)會(huì)重新生成一個(gè) traceId。
初步猜測(cè):
1)IdWorker 生成的隨機(jī)id重復(fù)了?
不太可能吧,IdWorker 用的是雪花算法啊,盡管在同一毫秒,并發(fā)量不高的話也不會(huì)生成重復(fù)的…
2) IdWorker 非單例的原因?
結(jié)論二:短時(shí)間內(nèi),存在 IdWorker 生成了重復(fù)的 traceId。
解決方案
-
關(guān)于第一個(gè)線程池透?jìng)?traceId 沒生效問題。主要有兩個(gè)原因:
1.1 項(xiàng)目壓根就沒有對(duì)線程池做 TTL 的包裝增強(qiáng)(也就是項(xiàng)目啟動(dòng)參數(shù)沒有加上 TTL 的 agent 方式代理),需要把參數(shù)給加上。
-javaagent:D:\AAA_pengyu\respository\com\alibaba\transmittable-thread-local\2.11.5\transmittable-thread-local-2.11.5.jar
1.2 實(shí)際上,盡管在所有項(xiàng)目把 TTL 的 agent 方式代理啟動(dòng)參數(shù)家加上也還是會(huì)失效的。前面說了,TTL 的 agent 代理與線上的 arm 監(jiān)控代理沖突。
針對(duì)和阿里云的溝通,修改方案如下:
-
關(guān)于 IdWorker 生成了重復(fù)的 traceId。
在測(cè)試調(diào)整過程中,我把IdWorker 改成單例模式之后,也還是會(huì)存在 id重復(fù)問題。
原因是構(gòu)造 IdWorker 時(shí) workerId,datacenterId,sequence 都為同一個(gè)字符串的原因,IdWorker 生成的 隨機(jī)id 是依賴這三個(gè)參數(shù)。
所以不同服務(wù)根據(jù)當(dāng)前機(jī)器ip、mac 等參數(shù)動(dòng)態(tài)生成就好了
最后,經(jīng)過如上的修改之后,公司的全鏈路日志追蹤就好了。