天天看點

RocketMQ x OpenTelemetry 分布式全鍊路追蹤最佳實踐

作者:阿裡開發者
作者簡介:艾陽坤,Apache RocketMQ PMC Member/Committer,CNCF OpenTelemetry Member,CNCF Envoy contributor。

在分布式系統中,多個服務之間的互動涉及到複雜的網絡通信和資料傳輸,其中每個服務可能由不同的團隊或組織負責維護和開發。是以,在這樣的環境下,當一個請求被發出并經過多個服務的處理後,如果出現了問題或錯誤,很難快速定位到根因。分布式全鍊路追蹤技術則可以幫助我們解決這個問題,它能夠跟蹤和記錄請求在系統中的傳輸過程,并提供詳細的性能和日志資訊,使得開發人員能夠快速診斷和定位問題。對于分布式系統的可靠性、性能和可維護性起到了非常重要的作用。

RocketMQ 5.0 與分布式全鍊路追蹤

Apache RocketMQ 5.0 版本作為近幾年來最大的一次疊代,在整個可觀測性上也進行了諸多改進。其中,支援标準化的分布式全鍊路追蹤就是一個重要的特性。

RocketMQ x OpenTelemetry 分布式全鍊路追蹤最佳實踐

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 概念被廣泛采用,并成為後來開源鍊路追蹤系統中的基礎概念之一。

RocketMQ x OpenTelemetry 分布式全鍊路追蹤最佳實踐

Dapper Trace Tree

在 Dapper 中,每個請求或事務被追蹤時都會建立一個 span,記錄整個請求或事務處理過程中的各個元件和操作的時間和狀态資訊。這些 span 可以嵌套,形成一個樹形結構,用于表示整個請求或事務處理過程中各個元件之間的依賴關系和調用關系。後來,很多開源鍊路追蹤系統,如 Zipkin 和 OpenTracing,也采用了類似的 span 概念來描述分布式系統中的鍊路追蹤資訊。現在,合并了 OpenTracing 和 OpenCensus 的 CNCF OpenTelemetry 自然也一樣采用了 span 概念,并在此基礎上進行了進一步發展。

OpenTelemetry 為 messaging 相關的 span 定義了一組語義約定(semantic convention)[2],旨在制定一套與特定消息系統無關的 specification,而 OpenTelmetry 自身的開發其實也都是由 specification 驅動進行展開。

RocketMQ x OpenTelemetry 分布式全鍊路追蹤最佳實踐

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 之間的組織關系是不同的:

RocketMQ x OpenTelemetry 分布式全鍊路追蹤最佳實踐

啟用 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]。

RocketMQ x OpenTelemetry 分布式全鍊路追蹤最佳實踐

然後準備好 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 請求。

RocketMQ x OpenTelemetry 分布式全鍊路追蹤最佳實踐

示例代碼調用鍊路

特别地,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。

剩餘60%,完整内容請點選下方連結檢視:

https://developer.aliyun.com/article/1181611?utm_content=g_1000369982

版權聲明:本文内容由阿裡雲實名注冊使用者自發貢獻,版權歸原作者所有,阿裡雲開發者社群不擁有其著作權,亦不承擔相應法律責任。具體規則請檢視《阿裡雲開發者社群使用者服務協定》和《阿裡雲開發者社群知識産權保護指引》。如果您發現本社群中有涉嫌抄襲的内容,填寫侵權投訴表單進行舉報,一經查實,本社群将立刻删除涉嫌侵權内容。

繼續閱讀