鏈路追蹤技術的應用及實踐

網易雲信發表於2020-07-09

分散式架構的興起推動了一些新技術的發展。其中鏈路追蹤技術以其在APM領域的優異表現,成為了分散式架構中不可或缺的一部分。在本文中,我們將談談它的一些經典應用場景,以及筆者所在的團隊如何利用鏈路追蹤技術提升團隊的研發效能。

一. 鏈路追蹤背景 enter image description here

如圖所示,在微服務體系中,一個請求往往需要多個服務協作處理。

凡事有利必有弊,這種模式在給我們帶來更好的可擴充套件性的同時,也帶來了一些新的問題。例如,排查問題的困難:任意節點的異常都可能導致上游鏈路的異常,難以追根溯源;系統拓撲復雜難以把控,健壯性存在隱患。

2010年,谷歌發表了一篇論文,介紹了谷歌的內部鏈路追蹤系統Dapper的設計,鏈路追蹤技術自此進入社群的視野。

下面,我們將簡單介紹其在APM領域的應用,以及在服務依賴治理和研發效能提升方面的實踐。

二. APM

分散式系統中,一個請求會在多個節點之間流轉,APM通過TraceID將整條請求處理鏈路中的相關節點關聯起來,並記錄每個節點的執行時間等資訊,形成請求的生命週期鏈路。 enter image description here

如圖,我們可以很直觀地看到請求經過了哪些節點,以及各個節點的處理耗時。這使得我們在關注服務本身執行狀態的同時,還能從請求生命週期的視角關注到整條請求鏈路上的所有細節及指標,大幅提高了我們排查定位問題的效率。

三. 服務依賴治理

不合理的依賴,可能導致邊緣系統的故障拖垮核心服務,威脅到分散式系統整體的穩定性。通過鏈路追蹤資料的彙總分析,我們可以繪製出系統間的依賴拓撲,為依賴治理提供資料支撐。 enter image description here

我們一般會從下面三個角度來評估服務依賴的合理性:

反向依賴。反向依賴指高等級服務依賴了低等級服務。例如,租戶服務是我們的核心服務之一,而統計服務重要性相對較低,顯然,我們不允許租戶服務依賴統計服務。通過服務拓撲圖和服務等級的結合,我們可以很容易的將反向依賴分析自動化,實時預警。

強弱依賴。強依賴指下游服務發生異常時,將影響當前節點的穩定性。在設計時,我們應該充分考慮強依賴在當前場景中的必要性。強依賴是否可以弱化,如果不能,業務場景是否允許加上熔斷降級之類的的保護措施。強弱依賴的梳理,我們可以結合故障注入工具,產出系統化的報告。

環狀依賴。環狀依賴往往是邊界不清晰的表現,絞成一團,層次不清。對環狀依賴的梳理也是我們對業務邊界和系統邊界的梳理,對系統整體健康度的提升非常有意義。

四. 研發效能提升

隨著業務的發展,研發團隊的規模在一定階段也會相應地不斷提升,但支撐我們研發活動的基礎設施卻沒有辦法線性增長,這其中最重要的就是聯調或測試環境。

業務發展往往導致並行迭代的增多,而這些並行迭代難免會改動到相同的服務,尤其是一些核心基礎服務。如下圖: enter image description here

這就會導致兩個問題——

  1. 環境爭奪。如圖,Story-B需要部署ticket服務,與此同時Hotfix-A也等待驗證,同樣需要部署ticket服務,這意味著至少有一方會被阻塞等待,這種序列模式,極大地降低了我們的交付效率。並行迭代越多,效率降低越明顯。

  2. 環境的穩定性。服務之間是相互聯絡的,任何服務的不穩定都可能會導致該環境的不穩定。上圖中的auth服務,幾乎要被所有的業務流程使用。如果Story-A部署auth服務時,重啟/部署的過程不夠平滑,或者Story-A的程式碼中存在某些bug,那麼會造成整個測試環境的不穩定。

專案規模不大時,我們往往能通過一些管理手段來協調。例如版本序列化,通過將迭代計劃錯開,避免在同一個時間段都要去部署某個服務。測試環境只部署特定分支,需要驗證時則將各自的程式碼都合併到此分支;要求部署到測試環境的程式碼必須達到某種標準以提升測試環境的穩定性。

然而我們也可以看到,管理手段的有效性是和團隊規模微服務規模反相關的,我們需要有技術手段來達到更好的效果。

細想一下,其實問題的根源是大家共用一套測試環境,所以我們的研發活動出現了資源競爭,我們對某個服務的操作可能影響到其他服務。

那麼,能否讓大家都能輕鬆建立各自的環境,且各個環境的使用互不影響呢?

enter image description here

如上圖,Story-A需要部署user和auth服務,那麼我們建立env-1並部署我們的user和auth; Story-B需要部署ticket服務,那麼我們就建立env-2並部署ticket服務;env-3同理。

為了描述方便,我們把上圖中的env-x環境,叫測試環境;圖中的下半部分,叫回歸環境。測試環境只包含本次迭代需要部署的應用,迴歸環境包含所有應用。

當我們使用這套機制時,我們期望env-1的使用者,請求user和auth服務時只會路由到env-1環境,請求其他服務時路由到迴歸環境。env-2環境的使用者,請求ticket服務時只會路由到env-2環境,請求其他服務時同樣路由到迴歸環境。

也就是說,對於環境使用者的請求,如果相關的應用在該環境內,則請求只會被該環境內的應用處理,否則路由到迴歸環境處理。

迴歸環境是一個包含所有服務的相對穩定的環境,開發和提測不允許在迴歸環境部署,以此來保證足夠的穩定性。

研發流程方面,我們不再像以前一樣部署到大家都在使用的環境中去驗證,而是各自建立各自獨享的環境,在自己的環境中完成相關工作。

我們將上述機制稱之為環境隔離,要實現環境隔離,技術側至少需要實現兩方面的能力: • 識別並傳遞請求對應的環境資訊 • ⼲預中介軟體的例項選擇/消費規則

識別並傳遞請求對應的環境資訊

首先,我們需要能將請求和測試環境關聯起來。

識別請求對應的環境資訊,這意味著我們在建立測試環境時需要指明某種標識,且這種標識我們可以從請求中提取出,從而通過雙方標識的匹配來完成關聯,這種標識可以是使用者賬號、某組IP,或者企業租戶,使用哪種方式不重要,重要的是結合業務特點達到方便易用的目的。

例如,在我們的SaaS系統七魚裡,我們使用租戶id來作為我們的標識。在我們的平臺建立測試環境時,除了指明要部署的應用外,我們還需要輸入租戶資訊,通過這種方式完成請求和測試環境的對映。

enter image description here

我們可以在請求的統一入口處(例如,閘道器),獲取到請求所屬的租戶,之後我們可以進一步拿到它所屬的環境資訊(環境ID、應用列表)。類似於鏈路跟蹤系統在請求鏈中傳輸TraceID,我們在請求鏈中附加上環境資訊,為環境隔離打下基礎。

⼲預中介軟體的例項選擇/消費規則

我們以微服務架構中最常用的幾個元件為例,談談環境隔離的實現方式。

RPC框架——

RPC的核心流程:provider例項將自己註冊到註冊中心,consumer通過註冊中心獲取provider例項列表,根據一定的例項篩選策略和負載均衡演算法,選擇其中一個例項發起呼叫。

所以改造的手段很明確,provider啟動時,我們在後設資料中寫入環境ID。在例項選擇時,我們從請求的鏈路資料中拿出環境ID與之做匹配。

需要特別注意的是,匹配不到符合要求的例項時,我們不能簡單的認為no provider而讓程式報錯,我們需要考慮該provider所屬的應用是否在對應環境應用列表中,如果不在,我們需要將請求路由到迴歸環境中。

enter image description here

訊息中介軟體——

RPC在呼叫之前有如上所述的例項篩選過程,但訊息中介軟體沒有這個邏輯,不過我們依然可以干預消費規則,即在消費者拿到訊息後判斷是丟棄訊息還是消費該訊息。以kafka為例,測試環境的kafka consumer啟動時,修改consumer groupid為groupid_${env}。kafka consumer接收到訊息時,執行和上述RPC框架篩選例項時類似的邏輯即可。

enter image description here

定時任務——

定時任務其實最為特殊。前文中我們提到,在請求的統一入口,查詢請求所對應的環境資訊並寫入鏈路。但是定時任務發起的請求並不是使用者觸發的,它來自系統內部,定時排程元件才是請求的“源頭”。所以我們需要在定時任務執行之初,就加入我們的判斷標識邏輯,這要求我們:

• 定時任務需要有統一的排程平臺,避免各業務模組姿勢各異,無法由通用元件統一處理 • 針對排程元件的任務分發/分片機制的改造,統一抽象執行層,加入環境隔離邏輯

五. 結束語

在網易智慧企業中,鏈路追蹤技術的應用,提升了我們的問題排查效率以及對請求鏈路的把控,也為服務依賴治理提供了必要的資料支撐。同時環境隔離也極大地提升了交付效率和測試環境的穩定性,從而提高了研發團隊的整體幸福感。

整體來說,我們構建了統一的鏈路追蹤體系,支撐了服務依賴治理及環境隔離技術的實現,但這並不是終點,我們還可以發掘更多的場景,比如SaaS系統的多租戶資源隔離,或者異常監控預警。世界很大,一起多探索。

相關文章