資訊處理流程 | 生成 | 收集 | 儲存 | 使用 |
---|---|---|---|---|
Jaeger | ✓ | ✓ | ✓ |
Jaeger 是由 Uber 於 2015 年 8 月開始開發的分散式追蹤(Distributed Tracing)工具。它具備完整的資料收集機制和查詢介面,而主要的儲存方式則支援 Cassandra 和 Elasticsearch。在 2017 年 9 月,Jaeger 成為 CNCF 的孵化專案,後於 2019 年 10 月晉升為畢業專案。除了支援 Jaeger 本身的自訂格式,它也支援 OpenTelemetry、Zipkin 等其他 API。過去,Jaeger 有自己維護的 SDK(Client Library),但該 SDK 自 2022 年 1 月發布最後一版後便不再進行維護(Sunsetting Jaeger clients),官方建議改用 OpenTelemetry SDK。
Jaeger 作者 Yuri Shkuro 在 2017 年於 Uber Blog 發表了「Evolving Distributed Tracing at Uber Engineering 」,這篇文章介紹了 Jaeger 的開發源由與發展軌跡。Uber 最初有一個僅供內部使用的第一代追蹤系統,名為 Merckx。但隨著系統變得越來越複雜,Merckx 不再符合需求。於是參考了 Dapper 與 Zipkin 的設計概念設計出了 Jaeger。Jaeger 是德文的獵人或狩獵助手的意思,發音為(ˈyā-gər),相當貼近分散式追蹤的主題,如追蹤、偵查和解決問題。
Jaeger 官網的 Getting Started 提供了一個 all-in-one 的版本。這個版本可以透過單一 Binary 或 Container 來啟動 Jaeger,並將所有資料儲存在記憶體中。但這個版本僅適用於初步體驗,因為一旦關閉 Jaeger,所有的資料就會遺失。在 Production 環境中,Jaeger 的後端通常會以分散式系統的方式分有多個 Component 運行,如下圖所示。
圖片來源:Jaeger
在本篇 Lab 所使用的範例即基於這樣的架構建立的,是參考官方的 docker compose example 範例修改而成。
這個架構主要包含三個部分:
在 Jaeger 較舊的版本中,可能還會看到一個名為 Jaeger Agent 的 Component。它主要用於加工和轉發 Trace Data,但自 1.43 版之後已經不再維護。若需類似功能,可選擇使用 OpenTelemetry Collector。
Jaeger 因具有較長的發展歷史,因此支援多種 API。了解自己所使用的 Trace Data 傳遞方式與格式極為重要,否則容易陷入無盡的排列組合除錯迴圈。標準的判斷方式為:確保 SDK 所選用的 Protocol 和格式與 Jaeger Collector 的 Port 是否相符。以下為常用的四個 Protocol 與 Port 對應,詳細說明可參考官方文件。
Collector Port | Collector Protocol | Data API | 功能 |
---|---|---|---|
14250 | gRPC | Protobuf via gRPC | 接收 Jaeger model.proto 格式的 Trace Data |
14268 | HTTP | Thrift over HTTP | 接收 Jaeger jaeger.thrift 格式的 Trace Data,並須加上 /api/traces Path |
4317 | gRPC | OpenTelemetry Protocol | 接收 OpenTelemetry 格式的 Trace Data,但 Collector 啟動時必須增加 --collector.otlp.enabled=true 參數啟用 |
4318 | HTTP | OpenTelemetry Protocol | 接收 OpenTelemetry 格式的 Trace Data,但 Collector 啟動時必須增加 --collector.otlp.enabled=true 參數啟用 |
從 v1.35 版本起,Jaeger Collector 開始支援 OpenTelemetry Protocol(OTLP)。因此,不再需要透過 OpenTelemetry Collector 轉換格式,可以直接使用 OpenTelemetry SDK 發送 Trace Data 至 Jaeger Collector。由於 Jaeger 開始正式支援 OTLP,OpenTelemetry SDK 中大部分支援 Jaeger 的 API 都將在 2023 年 7 月之後停止維護,未來也可能會被移除。因此,建議在選擇 API 時,優先使用 OTLP。
在 Distributed Tracing 中,每個 Request 都會產生大量的 Trace Data。若每筆 Trace 都進行儲存,會造成儲存成本過高。因此,需要透過採樣(Sampling)方式來只保留部分 Trace。Jaeger 提供了兩種採樣方式:
probabilistic
和基於每秒頻率的 ratelimiting
兩種方式。例如,可以設定讓 service foo
的 Trace Data 只有 80% 的機率被收集,或是每秒只收集 2 筆 service bar
的 Trace Data。採樣的設定方式是由 Jaeger Collector 提供採樣策略,並透過 sampling.proto 格式供服務輪尋取得。根據這些採樣策略,SDK 會決定是否要送出 Trace Data 給 Jaeger Collector。
SDK 需設定 JaegerRemoteSampler,並指定 Jaeger Collector 提供採樣策略的 endpoint
,一般為 http://<jaeger-collector>:14268/api/sampling
或 <jaeger-collector>:14250
。也可透過環境變數 OTEL_TRACES_SAMPLER
與 OTEL_TRACES_SAMPLER_ARG
進行設定,詳情可參考官方文件。
範例程式碼:21-jaeger
在範例中使用了四個方式來發送 Trace Data:
A. 透過 gRPC 發送 OTLP Trace Data 至 Jaeger Collector 的 4317 Port
B. 透過 HTTP 發送 OTLP Trace Data 至 Jaeger Collector 的 4318 Port
C. 透過 gRPC 發送 jaeger.thrift Trace Data 至 Jaeger Collector 的 14268 Port
D. 透過 HTTP 發送 model.proto Trace Data 至 Jaeger Collector 的 14250 Port
Jaeger Collector 會將 Trace Data 寫入 DB,Jaeger Query 則是從 DB 讀取 Trace Data 並提供 UI 查看。
啟動所有服務
docker-compose up -d
檢視服務
因 Cassandra 需要一些時間初始化,確認 Jaeger Collector 與 Jaeger Query 已啟動後,再繼續下一步
docker-compose ps
FastAPI App
Jaeger UI: http://localhost:16686
選擇 Service 後點選 Find Traces,即可看到 Trace Data
透過瀏覽器對 application 的 /chain
發送 Request,可以在 Trace 資訊中看到 app-a
、app-b
、app-c
互相呼叫的順序
或是使用 k6 發送 Request
k6 run --vus 1 --duration 300s k6-script.js
Grafana: http://localhost:3000,登入帳號密碼為 admin/admin
Jaeger
,可以查詢 Jaeger 的 Trace Data關閉所有服務
docker-compose down
Jaeger,作為一個經驗豐富並已晉升為 CNCF Graduated Project 的分散式追蹤系統,已被廣泛應用於生產環境中,同時也與時俱進和 OpenTelemetry 緊密結合,這都讓它能夠持續在微服務領域中發光發熱。
在深入研究 Jaeger 的過程中,才認識了 Jaeger 之父 Yuri Shkuro。他不僅對 Jaeger 有著重要的貢獻,還是 OpenTracing 和 OpenTelemetry 的 Co-founder 以及 W3C Trace Context 及 Baggage 規範的共同作者,更出版了一本 Mastering Distributed Tracing 分享他對 Tracing 的見解,從這裡更可以感受到這些天才橫溢的工程師們,真的是能夠憑一己之力推動整個領域的發展。