跟蹤在多執行緒非同步系統中傳遞

Mondo 科技 更新 2024-01-29

j**a 執行緒非同步的常見實現有:

new thread

executorservice

當然,還有其他的,例如:fork-join下面會提到這些,下面主要針對這兩個場景結合ddtrace和springboot練習。

1.8 1.21.0 com.datadoghq dd-trace-api $ io.opentracing opentracing-api 0.33.0 io.opentracing opentracing-mock 0.33.0 io.opentracing opentracing-util 0.33.0 ..
有關如何使用 DDTtrace SDK 的文件,請參閱文件ddtrace-api使用說明。

配置logback讓它輸出traceidspanid,將如下pattern適用於所有人appender中間。

如果生成了鏈路,則會在日誌中輸出跟蹤資訊。 

實現乙個簡單的介面來使用logback輸出日誌資訊並觀察日誌輸出。

@requestmapping("/thread") @responsebody public string threadtest()
請求後,日誌如下。

2023-10-23 11:33:09.983 [http-nio-8086-exec-1] info com.zy.observable.ddtrace.calcfilter - dofilter,28] springboot-server 7209831467195902001 958235974016818257 - start /threadhost localhost:8086connection keep-aliveuser-agent apache-httpclient/4.5.14 (j**a/17.0.7)accept-encoding br,deflate,gzip,x-gzip2023-10-23 11:33:10.009 [http-nio-8086-exec-1] info com.zy.observable.ddtrace.controller.indexcontroller - threadtest,277] springboot-server 7209831467195902001 2587871298938674772 - this func is threadtest.2023-10-23 11:33:10.022 [http-nio-8086-exec-1] info com.zy.observable.ddtrace.calcfilter - dofilter,34] springboot-server 7209831467195902001 958235974016818257 - 結束: 執行緒時間: 39
日誌中生成了跟蹤資訊traceidspanid向介面新增新執行緒以建立執行緒。

@requestmapping("/thread") @responsebody public string threadtest())start();return "success"; }
通過請求相應的 URL 來觀察日誌輸出。

2023-10-23 11:40:00.994 [http-nio-8086-exec-1] info com.zy.observable.ddtrace.controller.indexcontroller - threadtest,277] springboot-server 319673369251953601 5380270359912403278 - this func is threadtest.2023-10-23 11:40:00.995 [thread-10] info com.zy.observable.ddtrace.controller.indexcontroller - lambda$threadtest$1,279] springboot-server - this is new thread.
通過日誌輸出發現,new thread方式,並且無法輸出trace資訊,即trace它沒有通過。

如果我們顯示看跌期權trace可以把資訊傳進來嗎,就去做吧。

threadlocal當前執行緒唯一的區域性執行緒變數。

為了便於使用,讓我們建立乙個實用程式類threadlocalutil

public static final threadlocal thread_local = new threadlocal<>(
然後,將當前跨度資訊儲存到threadlocal

@requestmapping("/thread") @responsebody public string threadtest()",globaltracer.get().activespan().context().totraceid())new thread(()",threadlocalutil.getvalue())start();return "success"; }
通過請求相應的 URL 來觀察日誌輸出。

2023-10-23 14:14:02.339 [http-nio-8086-exec-1] info com.zy.observable.ddtrace.controller.indexcontroller - threadtest,278] springboot-server 4492960774800816442 4097884453719637622 - this func is threadtest.2023-10-23 14:14:02.340 [http-nio-8086-exec-1] info com.zy.observable.ddtrace.controller.indexcontroller - threadtest,280] springboot-server 4492960774800816442 4097884453719637622 - current traceid:44929607748008164422023-10-23 14:14:02.341 [thread-9] info com.zy.observable.ddtrace.controller.indexcontroller - lambda$threadtest$1,283] springboot-server - this is new thread.2023-10-23 14:14:02.342 [thread-9] info com.zy.observable.ddtrace.controller.indexcontroller - lambda$threadtest$1,284] springboot-server - new thread get span:null
在新執行緒中獲取外部執行緒threadlocal,得到的值為null通過分析threadlocal原始碼是在我們使用threadlocalset()方法threadlocal我在內部使用它thread.currentthread()原來如此threadlocal資料儲存key,即從新執行緒獲取變數資訊時,key有乙個變化,所以我不能接受乙個值。

public class threadlocal else }public t get() return setinitialvalue();
inheritablethreadlocal擴大threadlocal提供從父執行緒到子執行緒的值繼承: 建立子執行緒時,子執行緒將接收父執行緒具有值的所有可繼承執行緒區域性變數的初始值。

官方解釋:

this class extends threadlocal to provide inheritance of values from parent thread to child thread: when a child thread is created, the child receives initial values for all inheritable thread-local variables for which the parent has values. normally the child's values will be identical to the parent's; however, the child's value can be made an arbitrary function of the parent's by overriding the childvalue method in this class.inheritable thread-local variables are used in preference to ordinary thread-local variables when the per-thread-attribute being maintained in the variable (e.g., user id, transaction id) must be automatically transmitted to any child threads that are created.note: during the creation of a new thread, it is possible to opt out of receiving initial values for inheritable thread-local variables.
為了便於使用,讓我們建立乙個實用程式類inheritablethreadlocalutil.j**a儲存跨度資訊。

public static final inheritablethreadlocal thread_local = new inheritablethreadlocal<>(
threadlocalutil將其替換為inheritablethreadlocalutil

@requestmapping("/thread") @responsebody public string threadtest()",globaltracer.get().activespan().context().totraceid())new thread(()",inheritablethreadlocalutil.getvalue())start();return "success"; }
通過請求相應的 URL 來觀察日誌輸出。

2023-10-23 14:37:05.415 [http-nio-8086-exec-1] info com.zy.observable.ddtrace.controller.indexcontroller - threadtest,278] springboot-server 8754268856419787293 5276611939997441402 - this func is threadtest.2023-10-23 14:37:05.416 [http-nio-8086-exec-1] info com.zy.observable.ddtrace.controller.indexcontroller - threadtest,280] springboot-server 8754268856419787293 5276611939997441402 - current traceid:87542688564197872932023-10-23 14:37:05.416 [thread-9] info com.zy.observable.ddtrace.controller.indexcontroller - lambda$threadtest$1,283] springboot-server - this is new thread.2023-10-23 14:37:05.417 [thread-9] info com.zy.observable.ddtrace.controller.indexcontroller - lambda$threadtest$1,284] springboot-server - new thread get span:datadog.trace.instrumentation.opentracing32.otspan@712ad7e2
通過觀察上述日誌資訊,執行緒已經獲取到了span物件位址,但日誌pattern部分不是trace資訊輸出,原因是,ddtracelogbackge***cpropertymap()ge***c()方法並新增跟蹤資訊putmdc中間。

@advice.onmethodexit(suppress = throwable.class) public static void onexit( @advice.this iloggingevent event, @advice.return(typing = assigner.typing.dynamic, readonly = false) map mdc) agentspan.context context = instrumentationcontext.get(iloggingevent.class, agentspan.context.class).get(event); // nothing to add so return early if (context == null &&agenttracer.traceconfig().islogsinjectionenabled())map correlationvalues = new hashmap<>(8); if (context != null) else } string servicename = config.get().getservicename();if (null != servicename &&servicename.isempty())string env = config.get().getenv();if (null != env &&env.isempty())string version = config.get().getversion();if (null != version &&version.isempty())mdc = null != mdc ? new unionmap<>(mdc, correlationvalues) :correlationvalues; }
為了允許新建立的執行緒的日誌也獲取父執行緒的跟蹤資訊,可以通過建立它來實現span來實現這一目標span需要是父執行緒的子執行緒span完成串聯。

new thread(()",inheritablethreadlocalutil.getvalue())span span = null; try ",span.context().totraceid())finally }start();
通過請求相應的 URL 來觀察日誌輸出。

2023-10-23 14:51:28.969 [http-nio-8086-exec-1] info com.zy.observable.ddtrace.controller.indexcontroller - threadtest,278] springboot-server 2303424716416355903 7690232490489894572 - this func is threadtest.2023-10-23 14:51:28.969 [http-nio-8086-exec-1] info com.zy.observable.ddtrace.controller.indexcontroller - threadtest,280] springboot-server 2303424716416355903 7690232490489894572 - current traceid:23034247164163559032023-10-23 14:51:28.970 [thread-9] info com.zy.observable.ddtrace.controller.indexcontroller - lambda$threadtest$1,283] springboot-server - this is new thread.2023-10-23 14:51:28.971 [thread-9] info com.zy.observable.ddtrace.controller.indexcontroller - lambda$threadtest$1,284] springboot-server - new thread get span:datadog.trace.instrumentation.opentracing32.otspan@c3a1aae2023-10-23 14:51:28.971 [thread-9] info com.zy.observable.ddtrace.controller.indexcontroller - lambda$threadtest$1,292] springboot-server - thread:23034247164163559032023-10-23 14:51:28.971 [thread-9] info com.zy.observable.ddtrace.controller.indexcontroller - lambda$threadtest$1,294] springboot-server 2303424716416355903 5766505477412800739 - thread:2303424716416355903
為什麼執行緒中有兩個日誌pattern沒有跟蹤資訊輸出?原因在於當前執行緒的內部結構span它是在日誌輸出之後建立的,只需要放入span只需建立以下內容即可。

new thread(()",inheritablethreadlocalutil.getvalue())logger.info("thread:{}",span.context().totraceid())finally }start();
通過請求相應的 URL 來觀察日誌輸出。

2023-10-23 15:01:00.490 [http-nio-8086-exec-1] info com.zy.observable.ddtrace.controller.indexcontroller - threadtest,278] springboot-server 472828375731745486 6076606716618097397 - this func is threadtest.2023-10-23 15:01:00.491 [http-nio-8086-exec-1] info com.zy.observable.ddtrace.controller.indexcontroller - threadtest,280] springboot-server 472828375731745486 6076606716618097397 - current traceid:4728283757317454862023-10-23 15:01:00.492 [thread-9] info com.zy.observable.ddtrace.controller.indexcontroller - lambda$threadtest$1,291] springboot-server 472828375731745486 9214366589561638347 - this is new thread.2023-10-23 15:01:00.492 [thread-9] info com.zy.observable.ddtrace.controller.indexcontroller - lambda$threadtest$1,292] springboot-server 472828375731745486 9214366589561638347 - new thread get span:datadog.trace.instrumentation.opentracing32.otspan@12fd40f02023-10-23 15:01:00.493 [thread-9] info com.zy.observable.ddtrace.controller.indexcontroller - lambda$threadtest$1,293] springboot-server 472828375731745486 9214366589561638347 - thread:472828375731745486
建立 API 並直通executors創造executorservice物件。

@requestmapping("/execthread") @responsebody public string executorservicetest())return "executorservice"; }
通過請求相應的 URL 來觀察日誌輸出。

2023-10-23 15:24:41.828 [http-nio-8086-exec-1] info com.zy.observable.ddtrace.controller.indexcontroller - executorservicetest,309] springboot-server 2170215511602500482 4370366221958823908 - this func is executorservicetest.2023-10-23 15:24:41.832 [pool-2-thread-1] info com.zy.observable.ddtrace.controller.indexcontroller - lambda$executorservicetest$2,311] springboot-server 2170215511602500482 4370366221958823908 - this is executor thread.
executorservice執行緒池模式自動傳遞跟蹤資訊,該資訊派生自相應元件掩埋操作的 DDTRACE 實現。

J**A 支援許多執行緒元件框架的鏈結傳遞,例如:forkjointaskforkjoinpooltimertaskfuturetaskthreadpoolexecutor等一會。

springboot-ddtrace-server

相關問題答案

    以色列正處於多管齊下的困境中

    名稱 The Pain of History!中東戰爭再度火燃,以色列陷入多線困境,伊朗爭奪全球霸權,你的祖國也岌岌可危 標題 中東戰爭 歷史之痛再次襲來,讓我們站在一起!在中東這片土地上,歷史似乎總是與緊張和衝突密切相關。最近,該地區再次成為全球關注的焦點,原因無非是以色列與其鄰國 巴勒斯坦 黎巴...

    以色列繼續在多條戰線上作戰 聯合國駐黎巴嫩設施遭到襲擊

    新華社北京月日電 記者 張旭 日,以色列 黎巴嫩邊境緊張局勢仍在繼續 以色列遭到來自黎巴嫩方向的飛彈和自殺式無人機襲擊,以色列還動用了空襲和炮擊。聯合國駐黎巴嫩臨時部隊 聯黎部隊 設施遭到不確定的炮火襲擊 路透社援引以色列軍方訊息人士的話報道說,以色列軍隊出動多架戰機對黎巴嫩境內的若干安拉目標進行密...

    以色列發動了多線作戰,聯合國設施遭到襲擊

    以色列和黎巴嫩之間的緊張局勢依然存在。最近,以色列遭到來自黎巴嫩方向的飛彈和自殺式無人機襲擊,以色列對此作出回應。聯合國在黎巴嫩邊界的軍事設施也遭到襲擊。此外,黎巴嫩真主在乙份宣告中說,它發射了武裝無人機襲擊了以色列的乙個 指揮所 並對黎巴嫩邊境城鎮納古拉附近的以色列軍隊賈爾阿拉姆哨所發動了襲擊。據...

    擅自不上門罰款3萬元? 聆聽一線快遞員的心聲

    近日,交通運輸部聽取了關於年交通運輸更貼近民生的匯報,並審議了 快遞市場管理辦法 快遞市場管理辦法 修訂草案 徵求意見稿 已於年月日由國家郵政局發布,向社會公開徵求意見。我不知道到底收到了多少意見,但該法規中的許多規定都有些苛刻。對於草根網點和一線快遞員來說,最受詬病的一件事是 未經使用者同意,不得...

    振動清洗篩在油脂生產線中起什麼作用?

    菜籽油是從菜籽中提取的食用植物油,菜籽是我國主要的食用油之一,其產量佔國內食用油的 以上,深受中國消費者的喜愛。菜籽油又稱菜籽油,主要產於長江流域 我國西南和西北地區,富含脂肪 蛋白質 不飽和脂肪酸 酚類 肽類等營養成分,具有抗炎護膚 清肝和健膽等功能和功效。油菜籽作為我國主要的食用油料種子之一,為...