Observability 2.0 想傳遞的精神當中,其中一項就是不希望可觀測性實踐被工具所綁定。我們該如何確保可觀測性系統是能隨時切換或者擴展儲存後端的呢?
OpenTelemetry(或有些人會簡稱為 OTel)即是為了解決這樣的痛點而生。它是一個可觀測性的框架(framework)以及工具(toolkit),並且完全開源且不受廠商綁定。它提供標準化的 API 與 SDK,讓我們可以針對遙測資料(telemetry data, *註1)進行生成(Generate)、收集(Collect)以及匯出(Export)到儲存後端。
對於 OpenTelemetry 來說,它最主要的目的就是讓我們可以輕易地觀測自己的應用程式與系統,並且能做到跨平台、跨環境、跨程式語言的通用性,使得開發者能降低在收集遙測資料的難度。
由於它只負責做資料的生成、收集與導出,不像 Prometheus 這樣的工具擁有自己的儲存後端。但反過來說,它也給予 SRE 團隊極大的彈性,可以和非常多樣化的儲存後端做界接,包含 Prometheus 和 Jaeger 等。我們在上一篇文章討論的 columnar database,也可以和 OpenTelemetry 做整合。
因此,團隊在考慮導入 OpenTelemetry 時,必須要連同使用的 backend 及可視化工具一起選型。這兩者並不包含在 OpenTelemetry 的功能當中。
OpenTelemetry 整體的架構,可以看到從應用程式端到儲存後端的資料流
OTLP(OpenTelemetry Protocol)是由 OpenTelemetry 開發的傳輸協定,它規範了該如何編碼、傳輸與接收遙測資料,如此一來,不同的程式語言、服務、工具之間才能使用相同的格式進行通訊。
OTLP 定義了標準化的:
近年來,也越來越多服務支援 OTLP 格式,例如Claude、NGINX等。對於開發者來說,支援各種語言的 OpenTelemetry SDK 也能輕鬆匯出 OTLP 格式的遙測資料。
未來無論是導入新的第三方服務,還是開發新的內部系統,只要支援 OTLP 協定,就能無縫接入現有的可觀測性架構,避免重複的整合工作。
假設今天我們有一個微服務架構,不同的微服務使用 Java、Python、Go 三種語言寫成,若沒有標準化,三個微服務產生的遙測資料可能會有完全不同的命名規則,例如orderProcessingTime、payment_duration等。
OpenTelemetry 定義了一套語意約定(Semantic Conventions) 來解決這個問題。透過統一的命名規範,讓相同性質的指標在不同的服務中仍能保持一致。
若沒有標準化,各個服務傳來的資料可能會是:
user.id = '123'
user_id = '456'
userId = '789'
若遵循 OpenTelemetry 的語意約定,它可能會像是:
{
"traceId": "5B8EFFF798038103D269B633813FC60C",
"spanId": "051581bf3cb55c13",
"operationName": "process_order",
"duration": 150,
"attributes": {
"service.name": "order-service",
"service.version": "1.2.0",
"user.id": "user-123",
"http.method": "POST",
"http.status_code": 200
}
}
透過語意約定,我們可以使用統一的 user.id 追蹤同一個請求在不同微服務間的流動過程。同時,我們也不需要再額外記憶每個服務的特殊命名方式了。
OpenTelemetry 的模組化設計,每個元件都有清楚定義的職責,並且可以讓我們自由組合。
在這裡,Collector 扮演著核心樞紐的角色,它採用 Receiver - Processor - Exporter 的設計,且這三個環境都可以獨立配置並替換。
我們可以透過 Collector 的設定檔來充分了解這個設計理念:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
prometheus:
config:
scrape_configs:
- job_name: 'app-metrics'
static_configs:
- targets: ['localhost:8080']
processors:
batch:
timeout: 1s
send_batch_size: 1024
resource:
attributes:
- key: environment
value: production
action: insert
exporters:
prometheus:
endpoint: "0.0.0.0:8889"
jaeger:
endpoint: jaeger:14250
tls:
insecure: true
logging:
loglevel: debug
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch, resource]
exporters: [jaeger, logging]
metrics:
receivers: [otlp, prometheus]
processors: [batch, resource]
exporters: [prometheus, logging]
我們可以從設定檔當中看到 Collector 中的三個元件各司其職:
可以看到這樣的設計非常靈活。一個 Collector 不但可以接收多種格式的資料,還能將這些不同的資料進行格式的統一化(也就是符合 OTLP 的格式),再將資料送往不同的後端服務進行後續處理。
往後,若團隊有新的資料輸入源或者要改使用其他的儲存後端,我們只需要變更設定檔即可。
今天介紹了 OpenTelemetry 的設計理念,以及淺淺介紹了它是如何將這些理念給落地的。未來幾天,我們將會更深入地了解 OpenTelemetry 的各個核心元件及相關的部署策略。
*註1:遙測資料 (Telemetry Data) 指的是系統運行時產生的各種可觀測資料,包括 traces(追蹤)、metrics(指標)和 logs(日誌)。
Charity Majors, Liz Fong-Jones, George Miranda 著. 可觀測性工程|達成卓越營運. 呂健誠譯. 歐萊禮, 2023.
NGINX - Module ngx_otel_module
OpenTelemetry Docs - Component
OpenTelemetry Docs - OTLP Specification 1.8.0
OpenTelemetry Docs - What is OpenTelemetry?