全部產品
Search
文件中心

Managed Service for OpenTelemetry:基本概念

更新時間:Jul 06, 2024

本文介紹在使用Managed Service for OpenTelemetry之前需要瞭解的基本概念,包括分布式追蹤系統的作用,什麼是調用鏈,Managed Service for OpenTelemetry所依賴的OpenTracing資料模型,以及在Managed Service for OpenTelemetry產品裡資料是如何上報的。

為什麼需要分布式追蹤系統?

為了應對各種複雜的業務,開發工程師開始採用敏捷開發、持續整合等開發方式。系統架構也從單機大型軟體演化成微服務架構。微服務構建在不同的軟體集上,這些軟體模組可能是由不同團隊開發的,可能使用不同的程式設計語言來實現,還可能發布在多台伺服器上。因此,如果一個服務出現問題,可能導致幾十個應用都出現服務異常。

分布式追蹤系統可以記錄請求範圍內的資訊,例如一次遠程方法調用的執行過程和耗時,是我們排查系統問題和系統效能的重要工具。

什麼是調用鏈(Trace)?

在廣義上,一個調用鏈代表一個事務或者流程在(分布式)系統中的執行過程。在OpenTracing標準中,調用鏈是多個Span組成的一個有向非循環圖(Directed Acyclic Graph,簡稱DAG),每一個Span代表調用鏈中被命名並計時的連續性執行片段。

下圖是一個分布式調用的例子:用戶端發起請求,請求首先到達負載平衡器,接著經過認證服務、計費服務,然後請求資源,最後返回結果。

圖 1. 分布式調用樣本

資料被採集儲存後,分布式追蹤系統一般會選擇使用包含時間軸的時序圖來呈現這個調用鏈。

圖 2. 包含時間軸的鏈路圖

OpenTracing資料模型

整體概念

OpenTracing中的調用鏈(Trace)通過歸屬於此調用鏈的Span來隱性地定義。一條調用鏈可以視為一個由多個Span組成的有向非循環圖(DAG圖)。Span之間的關係被命名為References。例如下面的樣本調用鏈就是由8個Span組成的。

單個Trace中Span間的因果關係


        [Span A]  ←←←(The root span)
            |
     +------+------+
     |             |
 [Span B]      [Span C] ←←←(Span C是Span A的子節點,ChildOf)
     |             |
 [Span D]      +---+-------+
               |           |
           [Span E]    [Span F] >>> [Span G] >>> [Span H]
                                       ↑
                                       ↑
                                       ↑
                         (Span G在Span F後被調用, FollowsFrom)

有些情況下,使用下面這種基於時間軸的時序圖可以更好地展現調用鏈。

單個Trace中Span間的時間關係


––|–––––––|–––––––|–––––––|–––––––|–––––––|–––––––|–––––––|–> time

 [Span A···················································]
   [Span B··············································]
      [Span D··········································]
    [Span C········································]
         [Span E·······]        [Span F··] [Span G··] [Span H··]

鏈路

Tracer介面用於建立SpanstartSpan函數)、解析上下文(Extract函數)和透傳上下文(Inject函數)。它具有以下能力:

  • 建立一個新Span或者設定Span屬性

    /** 建立和開始一個span,返回一個span,span中包括操作名稱和設定的選項。
    ** 例如: 
    **    建立一個無parentSpan的Span:
    **    sp := tracer.StartSpan("GetFeed")
    **  建立一個有parentSpan的Span
    **    sp := tracer.StartSpan("GetFeed",opentracing.ChildOf(parentSpan.Context()))
    **/
    StartSpan(operationName string, opts ...StartSpanOption) Span

    每個Span包含以下對象:

    • Operation name:操作名稱 (也可以稱作Span name)。

    • Start timestamp:起始時間。

    • Finish timestamp:結束時間。

    • Span tag:一組索引值對構成的Span標籤集合。索引值對中,鍵必須為String,值可以是字串、布爾或者數字類型。

    • Span log:一組Span的日誌集合。每次Log操作包含一個索引值對和一個時間戳記。索引值對中,鍵必須為String,值可以是任意類型。

    • SpanContext: Span內容物件。每個SpanContext包含以下狀態:

      • 要實現任何一個OpenTracing,都需要依賴一個獨特的Span去跨進程邊界傳輸當前調用鏈的狀態(例如:Trace和Span的ID)。

      • Baggage Items是Trace的隨行資料,是一個索引值對集合,存在於Trace中,也需要跨進程邊界傳輸。

    • References(Span間關係):相關的零個或者多個Span(Span間通過SpanContext建立這種關係)。

  • 透傳資料

    透傳資料分為兩步:

    1. 從請求中解析出SpanContext。

      // Inject() takes the `sm` SpanContext instance and injects it for
      // propagation within `carrier`. The actual type of `carrier` depends on
      // the value of `format`.
      /** 根據format參數從請求(Carrier)中解析出SpanContext(包括traceId、spanId、baggage)。
      ** 例如: 
      **  carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
      **  clientContext, err := tracer.Extract(opentracing.HTTPHeaders, carrier)
      **/
      Extract(format interface{}, carrier interface{}) (SpanContext, error)
    2. 將SpanContext注入到請求中。

      /**
      ** 將SpanContext中的traceId,spanId,Baggage等根據format參數注入到請求中(Carrier),
      ** e.g 
      ** carrier := opentracing.HTTPHeadersCarrier(httpReq.Header)
      ** err := tracer.Inject(span.Context(), opentracing.HTTPHeaders, carrier)
      **/
      Inject(sm SpanContext, format interface{}, carrier interface{}) error

資料是如何上報的?

不通過Agent而直接上報資料的原理如下圖所示。

圖 3. 直接上報資料

通過Agent上報資料的原理如下圖所示。

圖 4. 通過Agent上報資料