1. 程式人生 > 其它 >微服務架構學習與思考(09):分散式鏈路追蹤系統-dapper論文學習

微服務架構學習與思考(09):分散式鏈路追蹤系統-dapper論文學習

一、技術產生的背景

1.1 背景

先來了解一下分散式鏈路追蹤技術產生的背景。


在現在這個發達的網際網路世界,網際網路的規模越來越大,比如 google 的搜尋,Netflix 的視訊流直播,淘寶的購物等。

像這種大規模的應用,我們每點選一下滑鼠,搜尋一個關鍵字,背後可能會有幾百臺伺服器上的N個服務來為我們提供服務。

我們用谷歌搜尋:分散式 3 個字,搜尋一些文章來學習分散式的知識。假如,查詢時結果返回耗時 5 秒之多。

作為使用者的你,等待這麼長時間才返回結果,心裡肯定不滿意。

那作為一項服務來說,公司為了更好的服務使用者,讓使用者滿意,就必須要縮短使用者等待返回查詢結果的時間,要儘可能快的返回結果。

這樣使用者使用時才會感覺滿意。


當然,這個優化任務就落在了產品技術研發人身上了。- -!

作為開發服務的產品技術人員,要怎麼樣做,才能讓使用者搜尋時返回結果很快呢?


這時,產品研發人就思考在思考:

使用者的一次搜尋背後可能有幾百個後端服務來提供服務。比如現在流行的微服務架構。

如果後端有一條服務比較慢,那麼就可能會拖慢這整個搜尋結果。

在這麼多的服務中,要怎麼樣做,才能找出慢的服務呢?怎麼找出是哪一條後端服務比較慢呢?

產品技術研發研究人員為了解決這個問題,慢慢想出了分散式鏈路追蹤的技術,在到具體的技術實踐,這是一個漫長的過程。

他們把研究成果匯聚在了 dapper 論文裡。

當然它也借鑑了前人的研究成果 ,尤其是

MagpieX-Trace,還有 Pinpoint

說明:這裡的 Pinpoint 並不是 pinpoint-apm,而是一篇論文


在 [dapper](https://research.google/pubs/pub36356/) 論文開頭有這樣一段描述:

Modern Internet services are often implemented as complex, large-scale distributed systems. These applications are constructed from collections of software modules that may be developed by different teams, perhaps in different programming languages, and could span many thousands of machines across multiple physical facili- ties. Tools that aid in understanding system behavior and reasoning about performance issues are invaluable in such an environment.

from: https://research.google/pubs/pub36356/

大意是說現代互連網服務,通常都是用複雜的、大規模分散式叢集來實現。這些應用構建在不同的模組上,這些軟體模組,可能由不同的團隊開發,可能使用不同的開發語言,可能部署在幾千臺伺服器上,橫跨多個數據中心。因此,需要一些可以理解這個複雜系統的行為,用於分析效能找出效能問題的工具。

1.2 一個請求的鏈路圖示

Dapper 論文裡的一張圖,表示一個請求可能經過的路徑節點:

(圖 1:這個路徑由user使用者的RequestX發起請求,穿過一個簡單的服務系統。用字母標識的節點代表分散式系統中的不同處理過程,

來自:https://research.google/pubs/pub36356/)

這張圖是由 5 臺伺服器提供相關的一個服務,它包含:A-前端,B,C-2個服務中間層,以及 2 個後端 D 和 E。

當一個使用者發起一個請求,首先是到達前端 A, 然後傳送 2 個 RPC 請求到伺服器 B 和 C。B 馬上會響應請求,但是 C 需要和

後端的 D 和 E 互動之後在返回給 A,最後由 A 來響應最初的請求。

上圖的呼叫鏈經過了不同的系統,這個系統可能是不同團隊維護,並且使用不同的語言開發。如果服務中出現了問題,比如請求異常,請求超時,那麼怎麼定位是哪個系統的哪一步出現了問題呢?

還有,對系統的監控是 7x24 小時不間斷的。持續的對系統進行監控。

二、Dapper 的分散式追蹤

2.1 怎麼定義圖1鏈路資訊

對於上面圖 1 的一個請求響應路徑,怎麼定義、怎麼能實現分散式追蹤呢?

簡單實現:為伺服器每一次的傳送和接收請求來收集追蹤標識(message identifiers)和時間戳(timestamped events)。

從入口開始發起 Request 的請求者(圖 1 中的 RequestX),與這個請求者相關的資訊都要關聯上,並記錄下來分析鏈路關係,有什麼好的方案呢?

2 種方案:黑盒(black-box)和基於標註(annotation-based)的監控方案。

黑盒方案:

假定需要追蹤的除了上述資訊之外沒有額外的資訊,這樣使用統計迴歸技術來推斷兩者之間的關係。

基於標註方案:

依賴於應用程式或中介軟體明確地標記一個全域性 ID,從而連線每一條記錄與發起者的請求。


2種方案的比較:

黑盒方案比標註方案跟輕便,但是它需要更多的資料,以獲得足夠的精度,因為他們依賴於統計推論。

標註方案最主要缺點,需要程式碼植入。


Google的選擇:

在 google 的生產環境中,所有的應用程式都使用相同的執行緒模型,控制流和RPC系統,他們可以把程式碼植入限制在一個很小的通用元件庫中,從而實現了監測系統的應用對開發人員是有效且透明。

dapper 的追蹤架構是內嵌在 RPC 呼叫鏈的屬性結構裡。當然這個呼叫鏈路監控,還可以追蹤其他行為,比如外界的 HTTP 請求,Gmail的 SMTP 會話和外部對 SQL 伺服器查詢等。

2.2 Dapper 資料結構模型

1、樹形結構,追蹤樹

2、Span 以及 Annotation

(圖 2:來自dapper論文:https://research.google/pubs/pub36356/)

  1. 圖 2,是一個樹形結構,每一個樹節點是整個架構的基本單元,這個節點單元叫做 span,每個節點 span 都有一個唯一的 id:span id,還有一個 name:span name。

  2. 節點之間的關係可以用父子來表示,parent id 和 span id,parent id 就是它上一個 span 的 id;如果一個 span 沒有父 id,那麼它就是根節點,root span。

  3. 所有的 span 都有一個追蹤請求 id,叫 trace id,作用是標識出一次完整請求。這個 trace id 是全域性唯一。

  4. 最後,每個 span 還有一個 Annotations,記錄每個 span 中的其他相關資訊,比如 span 的開始時間戳,結束時間戳,傳送資訊等等資訊,客戶端和服務端資訊都可以記錄。

(圖3:表示一個單獨的 span 結構資訊圖,來自 dapper 論文)

// 偽碼錶示結構
struct span {
    id        // 當前 span 的 id
    parent_id // 父 id,上一層 span id
    name      // 當前 span 的 name
    trace_id  // 標識一次完整請求的 trace_id
    Annotations []annotation // 表示 span 中的其它相關資訊
}

struct annotation {
    star_time  // 此次 span 開始時間戳
    end_time   // 此次 span 結束時間戳
    client_send_info  // 客戶端傳送資訊
    client_recv_info  // 客戶端接收資訊
    server_send_info  // 服務端傳送資訊
    .. ...
}

2.3 怎麼把追蹤程式碼值入相關程式中

dapper 裡面叫植入點

怎麼把相關追蹤程式碼放入到程式中?並且能比較少的改動程式碼,又能達到下面三個設計目標。


dapper 裡提了 3 個設計目標:
  1. 低損耗

追蹤系統對線上服務的影響最小化。因為在一些效能比較敏感的服務裡,一點點的效能消耗也可能影響使用者體驗。

  1. 對應用程式透明

對於應用程式來說,它根本覺察不到追蹤系統的存在。

一個追蹤系統,如果需要應用開發者主動配合植入追蹤程式碼,那麼追蹤系統的存在不僅會導致眾多額外程式碼的修改,最重要的是可能會使

執行良好的系統產生bug。

  1. 擴充套件性

google 在未來幾年隨著業務規模增長而擴充套件叢集規模,追蹤系統也能夠應對這種情況。


對於上面 3 點中最重要的一點就是追蹤系統對**應用程式透明**。

那怎麼做才能對應用程式透明?

Dapper 可以近乎零浸入的成本對應用程式鏈路進行追蹤,得益於 google 的服務設施依賴幾個少數的通用元件庫,只要改造這

幾個元件庫就可以了。比如 google 中幾乎所有程序間通訊都是建立在 C++ 和 Java 開發的 RPC 框架上,那麼我們只用改造這個 RPC 框架,追蹤系統就能在依賴這個 RPC 框架的應用程式裡生效。

當然 dapper 也允許應用開發人員給鏈路追蹤系統新增額外的資訊,以監控更高級別的系統行為,或幫助除錯問題。它允許使用者通過一個簡單的 API 定義帶時間戳的 Annotation。

2.4 取樣率和追蹤資訊的收集

低損耗是 dapper 的一個設計目標,所以 dapper 對系統鏈路資訊收集工作對基本元件效能損耗要儘可能的小。還有就是遇到大量請求時只記錄其中一小部分。

(圖4:dapper 收集管道總覽,來自 dapper 論文)

dapper 追蹤系統記錄和收集資訊過程分為三個階段(如上圖4):

  1. span 的資料寫入(1)本地日誌檔案,
  2. 然後 dapper 的 daemon 程序和收集元件把追蹤的資料從生產環境讀取處理(2)。
  3. 最後一些(3)的 bigtable 倉庫中。

看上面圖4:一次追蹤資訊被儲存為 bigtable 的一行,每一列相當於一個 span。

引用參考