作者簡介:艾陽坤,Apache RocketMQ PMC Member/Committer,CNCF OpenTelemetry Member,CNCF Envoy contributor。
在分佈式系統中,多個服務之間的交互涉及到複雜的網絡通信和數據傳輸,其中每個服務可能由不同的團隊或組織負責維護和開發。因此,在這樣的環境下,當一個請求被髮出並經過多個服務的處理後,如果出現了問題或錯誤,很難快速定位到根因。分佈式全鏈路追蹤技術則可以幫助我們解決這個問題,它能夠跟蹤和記錄請求在系統中的傳輸過程,並提供詳細的性能和日誌信息,使得開發人員能夠快速診斷和定位問題。對於分佈式系統的可靠性、性能和可維護性起到了非常重要的作用。
RocketMQ 5.0 與分佈式全鏈路追蹤
Apache RocketMQ 5.0 版本作爲近幾年來最大的一次迭代,在整個可觀測性上也進行了諸多改進。其中,支持標準化的分佈式全鏈路追蹤就是一個重要的特性。
RocketMQ 5.0 可觀測
而由 Google、Microsoft、Uber 和 LightStep 聯合發起的 CNCF OpenTelemetry 作爲 OpenTracing 和 OpenCensus 的官方繼任者,已經成爲可觀測領域的事實標準,RocketMQ 的分佈式全鏈路追蹤也圍繞 OpenTelemetry 進行展開。
分佈式鏈路追蹤系統的起源可以追溯到 2007 年 Google 發佈的 **《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》 [ 1] **論文。這篇論文詳細介紹了 Google 內部使用的鏈路追蹤系統 Dapper,其中使用的 span 概念被廣泛採用,併成爲後來開源鏈路追蹤系統中的基礎概念之一。
Dapper Trace Tree
在 Dapper 中,每個請求或事務被追蹤時都會創建一個 span,記錄整個請求或事務處理過程中的各個組件和操作的時間和狀態信息。這些 span 可以嵌套,形成一個樹形結構,用於表示整個請求或事務處理過程中各個組件之間的依賴關係和調用關係。後來,很多開源鏈路追蹤系統,如 Zipkin 和 OpenTracing,也採用了類似的 span 概念來描述分佈式系統中的鏈路追蹤信息。現在,合併了 OpenTracing 和 OpenCensus 的 CNCF OpenTelemetry 自然也一樣採用了 span 概念,並在此基礎上進行了進一步發展。
OpenTelemetry 爲 messaging 相關的 span 定義了**一組語義約定(semantic convention) [ 2] **,旨在制定一套與特定消息系統無關的 specification,而 OpenTelmetry 自身的開發其實也都是由 specification 驅動進行展開。
Specification Driven Development
Messaging Span 定義
Specifaition 中描述了 messaging span 的拓撲關係,包括代表消息發送、接收和處理的不同 span 之間的父子和鏈接關係。關於具體的定義可以參考:**Semantic Conventions of Messaging [ 3] **。對應到 RocketMQ 中,有三種不同的 span:
Span | Description |
---|---|
send | 消息的發送過程。span 以一次發送行爲開始,成功或者失敗/拋異常結束。消息發送的內部重試會被記錄成多條 span。 |
receive | 消費者中接收消息的長輪詢過程,與長輪詢的生命週期保持一致。 |
process | 對應 PushConsumer 裏 MessageListener 中對消息的處理過程,span 以進入 MessageListener 爲開始,離開 MessageListener 爲結束。 |
特別地,默認情況下,receive span 是不啓用的。在 receive span 啓用和不啓用的兩種情況下,span 之間的組織關係是不同的:
啓用 receive span 前後的 span 關係
在沒有啓用 receive span 的情況下,process span 會作爲 send span 的 child;而當 receive span 啓用的情況下,process span 會作爲 receive span 的 child,同時 link 到 send span。
Messaging Attributes 定義
語義約定中規定了隨 span 攜帶的通用屬性的統一名稱,這包括但不限於:
- messaging.message.id: 消息的唯一標識符。
- messaging.destination:消息發送的目的地,通常是一個隊列或主題名稱。
- messaging.operation:對消息的操作類型,例如發送、接收、確認等。
具體可以查看 Messaging Attributes 的部分 [ 4] 。
特別地,不同的消息系統可能會有自己特定的行爲和屬性,**RocketMQ 也和 Kafka 以及 RabbitMQ 一起,將自己特有的屬性推進了社區規範中 [ 5] **,這包括:
Attribute | Type | Description |
---|---|---|
messaging.rocketmq.namespace | string | RocketMQ 資源命名空間,暫未啓用 |
messaging.rocketmq.client_group | string | RocketMQ producer/consumer 負載均衡組,5.0 只對 consumer 生效 |
messaging.rocketmq.client_id | string | 客戶端唯一標識符 |
messaging.rocketmq.message.delivery_timestamp | int | 定時消息定時時間,只對 5.0 生效 |
messaging.rocketmq.message.delay_time_level | int | 定時消息定時級別,只對 4.0 生效 |
messaging.rocketmq.message.group | string | 順序消息分組,只對 5.0 生效 |
messaging.rocketmq.message.type | string | 消息類型,可能爲 normal/fifo/delay/transaction,只對 5.0 生效 |
messaging.rocketmq.message.tag | string | 消息 tag |
messaging.rocketmq.message.keys | string[] | 消息 keys,可以有多個 |
messaging.rocketmq.consumption_model | string | 消息消費模型,可能爲 clustering/broadcasting,5.0 broadcasting 被廢棄 |
快速開始
在 OpenTelemetry 中有兩種不同的方式可以爲應用程序添加可觀測信息:
- Automatic Instrumentation:無需編寫任何代碼,只需進行簡單的配置即可自動生成可觀測信息,包括應用程序中使用的類庫和框架,這樣可以更方便地獲取基本的性能和行爲數據。
- Manual Instrumentation:需要編寫代碼來創建和管理可觀測數據,並通過 exporter 導出到指定的目標。這樣可以更靈活自由地控制用戶想要觀測的邏輯和功能。
在 Java 類庫中,前者是一種更爲常見的使用形式。RocketMQ 5.0 客戶端的 trace 也依託於 automatic instrumentation 進行實現。在 Java 程序中,automatic instrumentation 的表現形式爲掛載 Java agent。在過去的一年裏,我們將**基於 RocketMQ 5.0 客戶端的 instrumentation [ 6] **推入了 OpenTelemetry 官方社區。現在,只需要在 Java 程序運行時掛載上 OpenTelemetry agent,即可實現對應用程序透明的分佈式全鏈路追蹤。
除此之外,Automatic Instrumentation 和 Manual Instrumentation 並不衝突,Automatic Instrumentation 中所使用的關鍵對象會被註冊成全局對象,在 Manual Instrumentation 的使用方式中也可以非常方便的獲取。實現兩個 Instrumentation 共用一套配置,非常靈活和方便。
首先準備好 RocketMQ 5.0 Java 客戶端,可以參考 example [ 7] 進行消息的收發。關於 RocketMQ 5.0 的更多細節,歡迎大家參考和關注 rocketmq-clients 倉庫 [ 8] 和 **RocketMQ 官網 [ 9] **。
然後準備好 OpenTelemetry agent jar,可以從 OpenTelemetry 官方**下載最新 agent [ 10] **,在應用程序啓動時增加 -javaagent:yourpath/opentelemetry-javaagent.jar 即可。
可以通過設置 OTEL_EXPORTER_OTLP_ENDPOINT 環境變量來設置 OpenTelemetry collector 的接入點。
默認情況下,按照 OpenTelemetry 中關於 messaging 的規範,只有 send 和 process 的 span 會被啓用,receive 的 span 是默認不啓用的,如果想要啓用 receive span,需要手動設置 -Dotel.instrumentation.messaging.experimental.receive-telemetry.enabled=true。
場景最佳實踐
目前,主流的雲服務供應商都爲 OpenTelemetry 提供了良好的支持,阿里雲上的 SLS 和 ARMS 兩款可觀測產品都提供了基於 OpenTelemetry 的分佈式全鏈路追蹤服務。
爲了更好地展示分佈式全鏈路追蹤的過程,這裏提供了一個代碼示例:**rocketmq-opentelemetry [ 11] **。在這個代碼示例中,會啓動三個不同的進程,涉及三種不同類庫和業務邏輯之間的相互調用,展示了一個在分佈式環境較複雜中間件之間進行交互的典型案例。
請求首先會從 gRPC 客戶端發往 gRPC 服務端,在 gRPC 服務端收到請求之後,會向 RocketMQ 5.0 的 Producer 往服務端發送一條消息,然後再回復對應的 response 給客戶端。
在 RocketMQ 5.0 的 PushConsumer 接受到消息之後,會在 MessageListener 中使用 Apache HttpClient 往淘寶網發送一條 GET 請求。
示例代碼調用鏈路
特別地,gRPC 客戶端在發起具體的調用是在一個上游業務 span 的生命週期之內進行的,這個 span 我們稱之爲 ExampleUpstreamSpan。
RocketMQ 5.0 PushConsumer 在收到消息之後,也會在 MessageListener 裏執行其他的業務操作,也會有對應的 span,我們稱之爲 ExampleDownstreamSpan。那麼默認在 receive span 沒有啓用的情況下,按照開始時間的順序,會先後存在 7 個 span。分別是:
- ExampleUpstreamSpan。
- gRPC 客戶端請求 span。
- gRPC 服務端響應 span。
- RocketMQ 5.0 Producer 的 send span。
- RocketMQ 5.0 Producer 的 process span。
- HTTP 請求 span。
- ExampleDownstreamSpan。
RocketMQ 5.0 對接 SLS Trace 服務
首先在阿里雲日誌服務中創建 Trace 服務。然後獲取接入點,項目和實例名稱等信息,具體可以參考**使用 OpenTelemetry 接入 SLS Trace 服務 [ 12] **。
在補充好信息之後完成接入之後,稍等一會就可以看到對應的 Trace 信息已經被上傳到 SLS trace 服務中:
SLS Trace 服務分佈式全鏈路展示
Trace 服務其實是將相關數據存儲到日誌中,因此這些數據也可以通過 SLS 的 SQL 語法查詢得到。
通過 Trace 數據,我們可以很方便知道用戶的操作系統環境,Java 版本等一系列基礎信息。消息的發送延時,失敗與否,消息是否準時投遞到了客戶端,以及客戶端本地消費耗時,消費失敗與否等一系列有效信息,可以幫助我們十分有效地進行問題排查。
除此之外,SLS Trace 服務的 demo 頁也提供了基於 RocketMQ 5.0 定製的消息中間件大盤,生動展示了利用 Trace 數據得到的發送成功率,端到端延時等一系列指標。
- **消息中間件分析 Tab [ 13] **:展示利用 Trace 數據得到的包括髮送延時、發送成功率、消費成功率、端到端延時在內的一系列指標。
- **查看 RocketMQ Trace Tab [ 14] **:可以根據上一步得到的差錯長 message id 進行進一步的細粒度查詢。
消息中間件分析
RocketMQ 5.0 對接應用實時監控服務(ARMS)
首先進入應用實時監控服務 ARMS 控制檯,點擊接入中心中的 OpenTelemetry,選擇 java 應用程序下的自動探測,獲取啓動參數並修改至自己的 java 應用程序,具體可以參考**通過 OpenTelemetry 接入 ARMS [ 15] **。
配置好參數之後,啓動自己的相關應用程序,稍等一會兒,就可以在 ARMS Trace Explorer 裏看到對應的數據了。
Trace Explorer
還可以查看 span 之間的時序關係。
ARMS Trace Explorer 分佈式全鏈路追蹤展示
具體地,可以點進每個 span 查看詳細的 attributes/resources/events 等信息。除此之外,ARMS 還支持通過使用 OpenTelemetry Collector 轉發的形式來收集應用程序的 Trace 數據。
趨勢與思考
隨着現代應用程序架構的不斷演進,可觀測性的重要性日益凸顯。它不僅可以幫助我們快速發現和解決系統中的問題,還提高應用程序的可靠性和性能,同時也是實現 DevOps 的關鍵部分。在相關領域,也陸續誕生了像 DataDog 和 Dynatrace 這樣的明星公司。
近年來湧現了一些新興技術,如 eBPF(Extended Berkeley Packet Filter)和 Service Mesh 也爲可觀測領域提供了一些新的思路:
eBPF 可以在內核層面運行,通過動態注入代碼來監控系統的行爲。它被廣泛應用於實時網絡和系統性能監控、安全審計和調試等任務,並且性能影響很小,未來也可以作爲 continuous profiling 的一種選擇。Service Mesh 則通過在應用程序之間注入代理層實現流量管理、安全和可觀測性等功能。代理層可以收集和報告有關流量的各種指標和元數據,從而幫助我們瞭解系統中各個組件的行爲和性能。
Service Mesh 中反映出的技術趨勢很大一部分已經在 RocketMQ 5.0 proxy 中得到了應用,我們也在更多地將可觀測指標往 proxy 進行收斂。當前的 Trace 鏈路未來也在考慮和服務端一起進行關聯,並打造用戶側,運維側,跨多應用的全方位鏈路追蹤體系。除此之外還可以將 Trace 數據與 Metrics 數據通過 Exemplars 等技術進行聯動。實現面到線,線到點的終極排查效果。
在可觀測領域,RocketMQ 也在不斷探索和摸索更加領先的可觀測手段,以幫助開發者和客戶更快更省心地發現系統中的隱患。
春招啓動
阿里云云原生 RocketMQ 研發團隊實習生春招開啓啦,歡迎 24 年畢業的同學踊躍投遞。 一起參與 Apache 頂級項目 RocketMQ 研發,技術方向有分佈式、Log存儲、事件驅動、Serverless、消息計算、可觀測等等。是很難得的可以一邊做商業化一邊同時做開源的團隊。團隊內部非常關注大家的技術成長,高效工作,從不內卷。
📮 歡迎大家投遞簡歷到我的郵箱:
相關鏈接:
[1] 《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》https://storage.googleapis.com/pub-tools-public-publication-data/pdf/36356.pdf
[2] 一組語義約定(semantic convention)
[3] Semantic Conventions of Messaging
[4] Messaging Attributes 的部分
[5] RocketMQ 也和 Kafka 以及 RabbitMQ 一起,將自己特有的屬性推進了社區規範中
[6] 基於 RocketMQ 5.0 客戶端的 instrumentation
[7] example
[8] rocketmq-clients 倉庫
https://github.com/apache/rocketmq-clients
[9] RocketMQ 官網
[10] 下載最新 agent
[11] rocketmq-opentelemetry
https://github.com/aaron-ai/rocketmq-opentelemetry
[12] 使用 OpenTelemetry 接入 SLS Trace 服務
https://help.aliyun.com/document_detail/208894.html?spm=a2c4g.11186623.0.0.473f641cXr5AMo
[13] 消息中間件分析 Tab
[14] 查看 RocketMQ Trace Tab
[15] 通過 OpenTelemetry 接入 ARMS
https://help.aliyun.com/document_detail/407604.html
參考鏈接:
RocketMQ 5.0 客戶端:
https://github.com/apache/rocketmq-clients
OpenTelemetry Instrumentation for RocketMQ 5.0:
RocketMQ OpenTelemetry 示例:
https://github.com/aaron-ai/rocketmq-opentelemetry
點擊此處進入官網瞭解更多詳情