Prometheus 聯合創始人的警告:在使用 OpenTelemetry 生成 Metrics 前請三思!
大家好,我是Tony Bai。
在云原生可觀測性的世界里,OpenTelemetry (OTel) 正如日中天。它被譽為“可觀測性的未來”,承諾用一個統一的標準,終結 Metrics、Traces、Logs 各自為戰的混亂局面。無數的開發者和公司,都在熱情地擁抱這個“一次插樁,到處發送”的美好愿景。
但就在這股幾乎不可阻擋的浪潮中,一個權威的聲音卻發出了一個略顯刺耳的警告。
這個人,就是 Prometheus 的聯合創始人,Julius Volz。
在他最新的博文中,Julius 毫不客氣地指出:如果你正在使用 Prometheus 作為你的核心監控系統,并且你真正關心監控的質量和體驗,那么,在使用 OpenTelemetry SDK 生成 Metrics 前,請務必三思!
他認為,擁抱 OTel 這個“通用標準”的代價,可能是丟掉 Prometheus 作為一個完整監控系統的“靈魂”,并背上丑陋、低效和復雜的“技術債”。
你正在丟掉 Prometheus 的靈魂
Julius 首先尖銳地指出了一個哲學問題:Prometheus 不僅僅是一個“指標數據庫”,它是一個端到端的、有自己思想的監控系統。而 OTel 的“后端無關”設計,恰恰破壞了這種端到端的自洽性。當你選擇用 OTel 向 Prometheus 推送數據時,你正在放棄這些至關重要的原生特性:
失去靈魂:Target 健康監控 (up 指標)
Prometheus 最核心的設計之一就是 Pull 模型 + 服務發現。這意味著 Prometheus 主動拉取指標,它清楚地知道“哪些目標應該存在”以及“它們現在是否健康”。如果一個目標拉取失敗,Prometheus 會自動生成一個 up{job="demo"} = 0 的指標。你可以用一條簡單的 PromQL 告警規則 up == 0 來發現任何失聯的服務。
然而,當你使用 OTel 的 Push 模型時,Prometheus 變成了一個被動的“無情的數據接收器”。它無法再區分一個服務是“正常下線”還是“已經崩潰但沒來得及上報”。你可能擁有數百個已經死掉的服務進程,卻在監控圖表上一無所知。

失去優雅:丑陋的 PromQL 查詢
為了兼容 PromQL,OTel 的指標在進入 Prometheus 時,往往需要經過“魔改”。
- 命名沖突: OTel 允許在指標名中使用 .,而 Prometheus 的傳統是不允許的。所以,一個 OTel 指標 k8s.pod.cpu.time 在進入 Prometheus 后,會被翻譯成 k8s_pod_cpu_time_seconds_total。這種不一致性會給開發者帶來困惑。
- 繁瑣的查詢語法: 為了支持 OTel 更寬泛的字符集,如果你想查詢原始的 OTel 指標名,你的 PromQL 查詢會從優雅的 my_metric{...} 變成丑陋的 {"my.metric", ...}。
失去便利:復雜的標簽 Join
Prometheus 的 target labels(如 instance, job)會被自動附加到從該目標拉取的所有指標上。而 OTel 的 resource attributes(包含更多非關鍵元數據)則不會。為了避免高基數問題,大部分 OTel 的資源屬性被打包進了一個單獨的 target_info 指標里。
這意味著,如果你想在查詢時使用這些屬性,你必須寫出類似下面這樣繁瑣的 group_left join 查詢:
// 想加一個 k8s_cluster_name 標簽,查詢變得如此復雜
rate(http_server_request_duration_seconds_count[5m])
* on(job, instance) group_left(k8s_cluster_name)
target_info這些問題,都在不斷地增加你的認知負荷和工作復雜度。
性能鴻溝:Go SDK 的“血案”現場
如果說失去優雅和可靠性還不足以讓你警醒,那么接下來的硬核性能數據,可能會讓你大吃一驚。Julius 特別對比了 Prometheus Go SDK 和 OpenTelemetry Go SDK 在執行最常見操作——計數器遞增——時的性能。
結論是毀滅性的。
Julius 的基準測試顯示,在不同的并行度和標簽緩存條件下:
- 在最壞情況下,Prometheus Go SDK 比 OTel Go SDK 快 26 倍。
- 在有標簽緩存的最佳情況下,Prometheus Go SDK 甚至可以比 OTel Go SDK 快 53 倍!
- 更致命的是,Prometheus Go SDK 在所有情況下都實現了零新內存分配,而 OTel SDK 在設置標簽時則會持續產生內存分配。

為什么會有如此驚人的差距?
- 復雜性 vs. 專注性: OTel SDK 是一個試圖統一三駕馬車(Metrics, Traces, Logs)的龐大系統,內部抽象層次多,路徑長。而 Prometheus SDK 的目標極其單一和專注:用最高效的方式生成 Prometheus 指標。
- 主觀代碼體驗: Julius 更是用一個生動的例子佐證了這一點——他想在兩個 SDK 中找到核心的 Inc()函數實現。在 Prometheus Go SDK 中,他花了 5 秒;而在 OTel Go SDK 中,他在復雜的抽象和間接調用中迷失了 15 分鐘后,最終放棄了。
對于性能至關重要的 Go 后端服務來說,選擇 OTel SDK 進行指標插樁,無異于在你的性能快車道上,悄悄地鋪上了一層厚厚的瀝青。
結論:在“通用標準”與“原生體驗”之間做出選擇
Julius 的文章并非是否定 OpenTelemetry 的價值。OTel 作為一個中立的、后端無關的“可觀測性瑞士”,在構建異構系統、避免廠商鎖定的場景中,依然具有不可替代的戰略意義。
但他的警告是在提醒我們一個深刻的權衡:
- OpenTelemetry 的世界觀: 追求最大的通用性和互操作性。它是一個數據生成和傳輸的標準,它不關心數據最終如何被使用。
- Prometheus 的世界觀: 追求一個深度整合、端到端優化的系統體驗。它的每一個設計——從 Pull 模型到 PromQL 語法——都在為最終用戶能以最優雅、最高效的方式進行監控和告警服務。
如果你已經選擇 Prometheus 作為你的核心監控“城邦”,那么使用它原生的客戶端庫,并非是選擇“封閉”,而是選擇一個經過千錘百煉的、高度自洽的、性能卓越的解決方案。
所以,在你為下一個 Go 項目 go get OTel SDK 之前,請先問自己一個問題:我是在追求一個“放之四海而皆準”的通用標準,還是在追求一個能將我的核心工具發揮到極致的原生體驗?
答案,可能決定了你未來無數個夜晚的睡眠質量。
資料鏈接:https://promlabs.com/blog/2025/07/17/why-i-recommend-native-prometheus-instrumentation-over-opentelemetry/



















