iT邦幫忙

2026 iThome 鐵人賽

DAY 24
1
Kubernetes

從零到一:使用 K8S + GitOps 打造異構技術棧的資料分析平台系列 第 24

[Day 24] 分布式追蹤 (Distributed Tracing):使用 OpenTelemetry 洞察微服務間的流轉 —— 深入學習 OTel 與 Jaeger 的完整請求鏈路。

  • 分享至 

  • xImage
  •  

Day 24: 分布式追蹤 (Distributed Tracing):使用 OpenTelemetry 洞察微服務間的流轉

深入學習 OTel 與 Jaeger 的完整請求鏈路。

1. 為什麼需要分布式追蹤

登入這個動作看起來很單純,實際走過的路徑是:React → API Gateway (Node.js) → User Service (Java) → PostgreSQL。當這個請求變慢或出錯,光看單一服務的日誌只能看到片段——Gateway 的日誌顯示「請求耗時 800ms」,但看不出這 800ms 花在哪一段。分布式追蹤把跨服務的呼叫串成一條完整的鏈路 (Trace),每個環節是一個 Span,可以看到每個 Span 各花了多少時間。

2. 核心技術棧

  • OpenTelemetry (OTel):一套跨語言的追蹤標準與 SDK,Java、Node.js、Python 各自有對應的 library,但輸出格式統一(OTLP protocol),可以送到同一個後端。
  • Jaeger:接收 Span、儲存、並提供 UI 呈現完整的請求鏈路。

3. 三個服務的 OTel 配置

Wafer BI 的三個核心服務都已經接上 OTel,做法各不相同:

Java (User Service):透過 Java Agent 做無侵入式追蹤,不需要改動任何程式碼,啟動參數掛上 agent 即可:

CMD ["java", \
     "-javaagent:opentelemetry-javaagent.jar", \
     "-Dotel.service.name=user-service", \
     "-Dotel.exporter.otlp.endpoint=http://otel-collector-service.k8sdemo.svc.cluster.local:4318", \
     "-Dotel.exporter.otlp.protocol=http/protobuf", \
     "-jar", "app.jar"]

Python (FastAPI):手動在 main.py 配置 SDK 並用 FastAPIInstrumentor 掛上自動追蹤:

from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor

provider = TracerProvider(resource=Resource(attributes={"service.name": "wafer-bi-service"}))
provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter(
    endpoint=os.getenv("OTEL_EXPORTER_OTLP_ENDPOINT", "http://otel-collector-service.k8sdemo.svc.cluster.local:4317"),
    insecure=True,
)))
trace.set_tracer_provider(provider)
FastAPIInstrumentor.instrument_app(app)

Node.js (API Gateway):用 @opentelemetry/auto-instrumentations-node 自動追蹤 Express 的 middleware 鏈與 http-proxy-middleware 的代理呼叫。

三者都指向同一個 otel-collector-service,只是 protocol 不同(gRPC 4317 或 HTTP/protobuf 4318)。

4. 部署 Jaeger 並產生真實請求

本機測試用 Jaeger all-in-one(內建 OTLP receiver,不需要額外部署 Collector):

kubectl create deployment jaeger --image=jaegertracing/all-in-one:latest -n k8sdemo
kubectl set env deployment/jaeger COLLECTOR_OTLP_ENABLED=true -n k8sdemo

建一個名為 otel-collector-service 的 Service 指到這個 Deployment,三個服務不需要改任何設定就能連上——因為它們原本就是照這個 DNS 名稱寫死的。

透過 Gateway 實際打幾個請求(登入、查詢用戶清單、查詢晶圓 meta 資料),讓每一段呼叫鏈都留下真實 Span,然後在 Jaeger UI 檢視其中一條 Trace:

https://ithelp.ithome.com.tw/upload/images/20260826/20182549Hga23v7VaJ.png

▲ Jaeger Trace 詳情:從 API Gateway 的 JWT 中介層開始,跨進 Java User Service,最後落到 PostgreSQL 的 SQL 查詢與 Transaction Commit

這條 Trace 完整呈現了一次 GET /users 請求的六層深度:

  1. Express 的一連串 middleware(helmetMiddlewarecorsMiddlewarequery 等)
  2. authenticateToken——就是 Day 6 那個 JWT 驗證中介層,耗時 2.78ms
  3. 跨進 user-service(Java),子 Span 顯示 GET /users
  4. Spring Data JPA 的 UserRepository.findAll
  5. 實際送出的 SQL:SELECT com.k8sdemo.userservice...
  6. 資料庫 Transaction.commit

單看任何一個服務的日誌都看不到這個完整順序,但在 Trace 視圖裡一目了然——包括每一段各花了多少毫秒。

5. 跨語言的另一個例子

同一批流量裡,另一條 Trace 顯示 Gateway 呼叫 /api/meta 進入 Python 的 wafer-bi-service

https://ithelp.ithome.com.tw/upload/images/20260826/20182549jOGfH0KryL.png

▲ Jaeger Trace:Node.js Gateway 呼叫 Python FastAPI 的 /meta 端點

Node.js 與 Python 是完全不同的執行環境、不同的追蹤 SDK 實作,但因為都遵守 OTel 的 trace context 傳遞規範(透過 HTTP Header 的 traceparent 欄位),Jaeger 依然能把兩邊的 Span 接成同一條時間軸。這是 OTel 作為「廠商中立標準」的核心價值——不需要 Java 用一套追蹤系統、Python 再用另一套。

6. 小結

分布式追蹤解決了「請求跨語言時,問題出在哪一段」這個微服務架構的核心排查難題。明天回到資源管理的主題:HPA 如何根據負載自動調整副本數量。


上一篇
[Day 23] 監控體系 (二):設計 Wafer BI 專屬的監控 Dashboard —— 將技術指標轉化為直觀的圖表,快速掌握健康度。
下一篇
[Day 25] 彈性伸縮:根據負載自動擴展 (HPA) 的實戰配置 —— 讓叢集在高峰期自動增加副本,離峰期自動縮減省錢。
系列文
從零到一:使用 K8S + GitOps 打造異構技術棧的資料分析平台30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
雷N
iT邦研究生 1 級 ‧ 2026-08-26 10:10:18

k8s 內,Java/Python/Node 剛好都支援auto-instrument, 所以k8s生態更推薦直接用 otel operator 來注入這些機制,取代 SDK。開發團隊有客制化需求時,也只需要使用 OTEL API 即可。

卡洛特 iT邦新手 5 級 ‧ 2026-09-03 09:43:02 檢舉

感謝分享 查了一下 auto-instrument 方便很多耶,我再來改良看看,感謝你

我要留言

立即登入留言