OpenTracing APIs

cdh0805010118發表於2018-06-30

OpenTracing的多語言支援

目前官方OpenTracing API支援的平臺有:GoPythonJSObjective-CJavaC++。PHP和Ruby正在開發中。

Data Conventions 資料約定

OpenTracing APIs的設計和規範,對追蹤軟體開發和探針軟體開發都有通用指導意義;追蹤系統的開發者不必嚴格遵守指南,但是強烈推薦大家這麼做。

Spans

  1. Span命名 在上一章OpenTracing interface中提到的Span interface包含operation name、tags、logs和baggage。這些可以代表span中進行的工作型別,例如:RPC或者HTTP呼叫端點、執行SQL語句,一個程式、類庫或者模組名稱。使得這個span所附帶的資訊是很有價值的。
  2. Span結構 Span結構也是非常重要的,主要表示Span本身所帶重要資訊,以及Spans之間的關聯關係。後文具體介紹

Span Tag用例

Span Tag所攜帶的資訊,特定存在的常量Key,有Errors、HTTP、Sample等等。不同的底層會對這些資訊做一些其他處理。例如:獲取、刪除或者清空Span Tag下的所有資訊,這個使用時可能是用得到的,但是需要注意的是,這些額外的操作可能會對業務系統本身造成不良影響,所以請仔細斟酌這些額外的實現。

Errors

表示一個span例項的錯誤狀態,通過一個tag來標註。如果設定了一個span tag特定常量errors的值為true,這我們可以通過dashboard ui的tag查詢功能,查詢所有trace error列表,並通過tag的log日誌,檢視具體的web request錯誤資訊,快速定位。並可以對一段時間的所有traces error列表統計,並報表輸出。這個是非常重要的

Component Identification 元件定義

我們十分推薦庫或者模組為監控程式提供元件的定義,終端使用者可能會用擁有一個由框架和第三方混合提供的監控。例如:

  1. span tag的key:component,value:需要被監控的類庫、模組或者包的基本名稱;例如:httplibJDBCmongoose等;
  2. span tag的key:span.kind。value:client | server。指定這個span代表一個客戶端或者服務端。

如果引入的package都自帶分散式跟蹤系統監控標籤,則監控粒度就可以很容易的植入進來。

HTTP Server Tags

因為是http請求服務入口,所以這些都是在框架層做的事情。例如:

  1. span tag的key:http.url;value:url地址;如:http://www.google.com.hk
  2. span tag的key: http.method; value: get|post|head
  3. span tag的key:http.status_code; value: 200; 404; 503

Peer Tags

這個用於rpc服務使用,描述遠端請求過程中,請求呼叫的方向。(客戶端記錄下行訪問,服務端記錄上行訪問)。

  1. peer.hostname目標主機名,型別:string
  2. peer.ipv4目標IPv4地址,型別:string
  3. peer.ipv6目標IPv6地址,型別:string
  4. peer.port目標埠,型別:int
  5. peer.service目標服務名稱,string

peer翻譯:對等,比如:client設定tag的peer{hostname, ipv4, service , port ...},表示server的具體資訊;server設定tag的peer{hostname...}, 表示client的具體資訊。

Sampling取樣

OpenTracing API不強調取樣的概念。有些情況下,當業務量非常大時,如果業務使用了分散式追蹤系統功能,則可能會對業務系統的效能造成很大影響。如果追蹤系統產品本身實現了取樣的特性,可以支援多規則取樣,

  1. 流量規則;
  2. web request數量;
  3. 預期的指定trace(特定的訂單ID、支付ID、使用者ID,預先植入,追蹤特定請求trace);

對於以上三種都是非常有價值的取樣規則;span tag中有個取樣key:sampling.priority, value值為整數型別;

  1. value>0;追蹤系統儘可能保留這條trace;
  2. value=0;追蹤系統不儲存這條呼叫鏈;

如果此tag沒有提供,追蹤系統使用自己的預設取樣規則;

Logs

Logs日誌是輕量級trace日誌,與分散式日誌系統無關;它是記錄span事件日誌,例如:當span執行單元發生錯誤時,錯誤日誌儲存在span logs中event:error, message: 具體的錯誤資訊;

Inject和Extract

《OpenTracing——相關概念術語》一文中提到,spans之間的trace資訊攜帶,如果是是跨程式,需要把資料通過BaggageSpanContext攜帶,主要用於:

  1. rpc服務;
  2. 釋出-訂閱機制;
  3. 通用訊息佇列;
  4. HTTP請求呼叫;
  5. UDP傳輸和其他傳輸方式;

把攜帶資訊通過OpenTracing APIs中的Inject和Extract方法,在跨程式追蹤時進行寫入和讀取。

InjectExtract方式實現的設計,必須遵循以下要求:

  1. 必須不需要使用OpenTracing使用中的特定程式碼;
  2. 必須不需要針對每一種已知的跨程式通訊機制都處理;
  3. 這套傳播機制是最利於擴充套件的;

基本方法:Inject、Extract和Carriers

追蹤過程中的SpanContext可以被Inject方法注入到Carriers中,這個Carriers可以是一個介面或者一個資料載體。 並在跨程式間傳輸,OpenTracing標準包含兩種必須的Carriers格式,自定義的Carriers也是可以的。同時在這個Span的ChildOf中通過Extract方法抽取Carriers資訊,得到一個SpanContext。這個SpanContext表示被Inject到Carriers中的資訊。

Inject虛擬碼:

span_context = ...

carrier = {} // 初始化資料載體
// 把span_context存放到HTTP_HEADERS格式的資料載體中
tracer.inject(span_context, opentracing.Format.HTTP_HEADERS, carrier)

// 並把carrier載體資料寫入到跨程式呼叫client端的網路傳輸中。
for key, value in carrier:
    outbount_request.header[key] = value

Extrace虛擬碼:

inbound_request = ...

// 把跨程式服務端接收到的傳輸資料,按照指定的格式和欄位,抽取到span_context中
carrrier = inbound_request.headers
span_context = tracer.extract(opentracing.Format.HTTP_HEADERS, carrier)

// 並把tracer串聯起來,建立一個新的span
span = tracer.start_span("...", child_of=span_context)

Carrier格式:

所有的Carriers都有自己的格式。一般格式都以常量表達,例如:Binary, TextMap, HTTPHeaders常量或者字串指定;另一些,則通過Carriers的靜態型別指定。

自定義的Carriers格式:

分散式跟蹤系統底層的實現可以採用自定義的Carriers格式,進行Inject和Extract操作。例如: ArrrPC private RPC SubSystem,我們希望增加OpenTracing的資料在RPC請求過程中傳輸。虛擬碼:

span_context = ...
outbound_request = ...

try:
    // 嘗試使用自定義的carrier格式,把span_context寫入到資料載體中
    // 如果失敗,直接使用標準的HTTP_HEADERS格式封裝
    tracer.inject(span_context, arrrpc.ARRRPC_OT_CARRIER, carrier)

except opentracing.UnsupportedFormatException:

    carrier = {}
    tracer.inject(span_context, opentracing.Format.HTTP_HEADERS, carrier)

for key, value in carrier:
    outbound_request.header[key] = escape(value)

參考資料

opentracing文件中文版 ( 翻譯 ) 吳晟

相關文章