上一篇我們簡單demo了一下opentelemetry在NodeJS express 和 Python FastAPI的實作,並且透過Jaeger來查看 tracing data。本篇我們來探討trace的原理。
在之前對 Sentry 的討論中,我們知道 Sentry 是透過在每個請求的 headers 加上、或修改sentry-trace
這一欄,讓每個服務知道自己是屬於哪個trace id、父span是哪一個。
而這個機制也相似於 Opentelemetry 的 trace 協議。OpenTelemetry 使用 W3C Trace Context 的標準,其核心是 traceparent
、 tracestate
、baggage
等 headers,用來傳遞分佈式追蹤的上下文訊息。而traceparent
的規範為:${version}-${trace-id}-${parent-id}-${trace-flag}
一個trace代表一個完整的分佈式請求鏈路,它由多個span組成,每個span對應服務中的一個操作。
每個span表示一次具體的操作,它有開始時間、結束時間、以及相關的metadata。
上下文是跨多個span保持追蹤的關鍵。當某一個 span 啟動時,它會攜帶 span 上下文,包含了 trace-id
、span-id
等資料,從而確保所有的 span 都與同一個 trace 相關聯。
當一個服務接受到請求到時候,會先查看其headers有沒有traceparent
屬性;如果沒有的話,代表自己本身是 root-span ,要先創一個 trace-id、以及自身的 span-id ;而如果有的話,則從traceparent
header中解析、獲取這個請求的 trace-id、以及父span id。
而如果這個服務還需要發起請求的話,就在請求headers中也加上traceparent
、並且把 parent-id 這一項改為自己的span id,然後才發送請求給下一個服務,告訴它 who is your daddy.
當請求結束之後(正常結束或者異常),就會計算請求時間以及其他細項,記錄到該 span 中,並發送給定義好的 trace collector server(在之前的案例中,就是Jaeger)。
透過對 Opentelemtry sdk的研究,我們了解到 tracing data 的運作邏輯。接下來,我們會嘗試寫一個自己的 Javascript 版本 trace sdk。