什麼是鏈路追蹤?分佈式系統如何實現鏈路追蹤?

公衆號關注 傑哥的IT之旅 」, java

選擇「 星標 」, 重磅乾貨,第一 時間送達! mysql

在分佈式系統,尤爲是微服務系統中,一次外部請求每每須要內部多個模塊,多箇中間件,多臺機器的相互調用才能完成。在這一系列的調用中,可能有些是串行的,而有些是並行的。在這種狀況下,咱們如何才能肯定這整個請求調用了哪些應用?哪些模塊?哪些節點?以及它們的前後順序和各部分的性能如何呢?程序員

這就是涉及到鏈路追蹤。算法

什麼是鏈路追蹤?

鏈路追蹤是分佈式系統下的一個概念,它的目的就是要解決上面所提出的問題,也就是將一次分佈式請求還原成調用鏈路,將一次分佈式請求的調用狀況集中展現,好比,各個服務節點上的耗時、請求具體到達哪臺機器上、每一個服務節點的請求狀態等等。sql

鏈路追蹤的原理

衡量一個接口,咱們通常會看三個指標:編程

一、接口的 RT(Route-Target)你怎麼知道?
二、接口是否有異常響應?
三、接口請求慢在哪裏?微信

一、單體架構時代網絡

在創業初期,咱們的系統通常是單體架構,以下:架構

對於單體架構,咱們可使用 AOP(切面編程)來統計這三個指標,以下:分佈式

使用 AOP(切面編程),對本來的邏輯代碼侵入更少,咱們只須要在調用具體的業務邏輯先後分別打印一下時間便可計算出總體的調用時間。另外,使用 AOP(切面編程)來捕獲異常也可知道是哪裏的調用致使的異常。

二、微服務架構

隨着業務的快速發展,單體架構愈來愈不能知足須要,咱們的系統慢慢會朝微服務架構發展,以下:

在微服務架構下,當有用戶反饋某個頁面很慢時,雖然咱們知道這個請求可能的調用鏈是 A -----> C -----> B -----> D,但服務這麼多,並且每一個服務都有好幾臺機器,怎麼知道問題具體出在哪一個服務?哪臺機器呢?

這也是微服務這種架構下的幾個痛點:

一、排查問題難度大,週期長
二、特定場景難復現
三、系統性能瓶頸分析較難

分佈式調用鏈就是爲了解決以上幾個問題而生,它主要的做用以下:

一、自動採起數據
二、分析數據,產生完整調用鏈:有了請求的完整調用鏈,問題有很大機率可復現
三、數據可視化:每一個組件的性能可視化,能幫助咱們很好地定位系統的瓶頸,及時找出問題所在

經過分佈式追蹤系統,咱們能很好地定位請求的每條具體請求鏈路,從而輕易地實現請求鏈路追蹤,進而定位和分析每一個模塊的性能瓶頸。

三、分佈式調用鏈標準(OpenTracing)

OpenTracing 是一個輕量級的標準化層,它位於應用程序/類庫和追蹤或日誌分析程序之間。它的出現是爲了解決不一樣的分佈式追蹤系統 API 不兼容的問題。

OpenTracing 經過提供與平臺和廠商無關的 API,使得開發人員可以方便地添加追蹤系統,就像單體架構下的AOP(切面編程)同樣。

說到這裏,你們是否想過 Java 中相似的實現?還記得 JDBC 吧?JDBC 就是經過提供一套標準的接口讓各個廠商去實現,程序員便可面對接口編程,不用關心具體的實現。這裏的接口其實就是標準。因此,制定一套標準很是重要,能夠實現組件的可插拔。

OpenTracing 的數據模型,主要有如下三個:

  • Trace:一個完整請求鏈路

  • Span:一次調用過程(須要有開始時間和結束時間)

  • SpanContext:Trace 的全局上下文信息,如裏面有traceId

爲了讓你們更好地理解這三個概念,我特地畫了一張圖:

如圖所示,一次下單的完整請求就是一個 Trace。TraceId是這個請求的全局標識。內部的每一次調用就稱爲一個 Span,每一個 Span 都要帶上全局的 TraceId,這樣纔可把全局 TraceId 與每一個調用關聯起來。這個 TraceId 是經過 SpanContext 傳輸的,既然要傳輸,顯然都要遵循協議來調用。如圖所示,若是咱們把傳輸協議比做車,把 SpanContext 比做貨,把 Span 比做路應該會更好理解一些。

理解了這三個概念,接下來咱們就看看分佈式追蹤系統是如何採集圖中的微服務調用鏈。

咱們能夠看到底層有一個 Collector 一直在默默無聞地收集數據,那麼每一次調用 Collector 會收集哪些信息呢。

一、全局 trace_id:這是顯然的,這樣才能把每個子調用與最初的請求關聯起來
二、span_id: 圖中的 0,1,1.1,2,這樣就能標識是哪個調用
三、parent_span_id:好比 b 調用 d 的 span_id 是 1.1,那麼它的 parent_span_id 即爲 a 調用 b 的 span_id 即 1,這樣才能把兩個緊鄰的調用關聯起來。

有了這些信息,Collector 收集的每次調用的信息以下:

根據這些圖表信息顯然能夠據此來畫出調用鏈的可視化視圖以下:

因而一個完整的分佈式追蹤系統就實現了。

以上實現看起來確實簡單,但有如下幾個問題須要咱們仔細思考一下:

一、怎麼自動採集 span 數據:自動採集,對業務代碼無侵入
二、如何跨進程傳遞 context
三、traceId 如何保證全局惟一
四、請求量這麼多采集會不會影響性能

接下來,咱們來看看鏈路追蹤系統 SkyWalking 是如何解決以上四個問題的。

鏈路追蹤系統SkyWalking的原理

一、怎麼自動採集 span 數據

SkyWalking 採用了插件化 + javaagent 的形式來實現了 span 數據的自動採集,這樣能夠作到對代碼的無侵入性。插件化意味着可插拔,擴展性好。以下圖所示:

二、如何跨進程傳遞 context

咱們知道數據通常分爲 header 和 body,就像 http 有 header 和 body,RocketMQ 也有 MessageHeader,Message Body。body 通常放着業務數據,因此不宜在 body 中傳遞 context,應該在 header 中傳遞 context,如圖所示:

dubbo 中的 attachment 就至關於 header,因此咱們把 context 放在 attachment 中,這樣就解決了 context 的傳遞問題。

三、traceId 如何保證全局惟一

要保證全局惟一 ,咱們能夠採用分佈式或者本地生成的 ID。使用分佈式的話,須要有一個發號器,每次請求都要先請求一下發號器,會有一次網絡調用的開銷。因此 SkyWalking 最終採用了本地生成 ID 的方式,它採用了大名鼎鼎的 snowflow 算法,性能很高。

不過 snowflake 算法有一個衆所周知的問題:時間回撥,這個問題可能會致使生成的 id 重複。那麼 SkyWalking 是如何解決時間回撥問題的呢。

每生成一個 id,都會記錄一下生成 id 的時間(lastTimestamp),若是發現當前時間比上一次生成 id 的時間(lastTimestamp)還小,那說明發生了時間回撥,此時會生成一個隨機數來做爲 traceId。這裏可能就有同窗要較真了,可能會以爲生成的這個隨機數也會和已生成的全局 id 重複,是否再加一層校驗會好點。

這裏要說一下系統設計上的方案取捨問題了,首先若是針對產生的這個隨機數做惟一性校驗無疑會多一層調用,會有必定的性能損耗,但其實時間回撥發生的機率很小(發生以後因爲機器時間紊亂,業務會受到很大影響,因此機器時間的調整必然要慎之又慎),再加上生成的隨機數重合的機率也很小,綜合考慮這裏確實沒有必要再加一層全局惟一性校驗。對於技術方案的選型,必定要避免過分設計,過猶不及。

四、請求量這麼多,所有采集會不會影響性能?

若是對每一個請求調用都採集,那毫無疑問數據量會很是大,但反過來想一下,是否真的有必要對每一個請求都採集呢?其實沒有必要,咱們能夠設置採樣頻率,只採樣部分數據,SkyWalking 默認設置了 3 秒採樣 3 次,其他請求不採樣,如圖所示:

這樣的採樣頻率其實足夠咱們分析組件的性能了,按 3 秒採樣 3 次,這樣的頻率來採樣數據會有啥問題呢。理想狀況下,每一個服務調用都在同一個時間點,這樣的話每次都在同一時間點採樣確實沒問題。以下圖所示:

但在生產上,每次服務調用基本不可能都在同一時間點調用,由於期間有網絡調用延時等,實際調用狀況極可能是下圖這樣:

這樣的話就會致使某些調用在服務 A 上被採樣了,在服務 B,C 上不被採樣,也就無法分析調用鏈的性能。

那麼 SkyWalking 是如何解決的呢?

它是這樣解決的:若是上游有攜帶 Context 過來(說明上游採樣了),則下游將強制採集數據,這樣能夠保證鏈路完整。

SkyWalking 的基礎架構

SkyWalking 的基礎以下架構,能夠說幾乎全部的的分佈式調用都是由如下幾個組件組成的。

首先固然是節點數據的定時採樣,採樣後將數據定時上報,將其存儲到 ES, MySQL 等持久化層,有了數據天然而然可根據數據作可視化分析。

SkyWalking 的性能如何

以下是官方的測評數據:

圖中藍色表明未使用 SkyWalking 的表現,橙色表明使用了 SkyWalking 的表現,以上是在 TPS 爲 5000 的狀況下測出的數據,能夠看出,不管是 CPU,內存,仍是響應時間,使用 SkyWalking 帶來的性能損耗幾乎能夠忽略不計。

接下來咱們再來看 SkyWalking 與另外一款業界比較知名的分佈式追蹤工具 Zipkin、Pinpoint 的對比(在採樣率爲 1 秒 1 個,線程數 500,請求總數爲 5000 的狀況下作的對比)。

能夠看到在關鍵的響應時間上, Zipkin(117ms),PinPoint(201ms)遠遜於 SkyWalking(22ms)!從性能損耗這個指標上看,SkyWalking 完勝!

再看下另外一個指標:對代碼的侵入性如何。

ZipKin 是須要在應用程序中埋點的,對代碼的侵入強,而 SkyWalking 採用 javaagent + 插件化這種修改字節碼的方式能夠作到對代碼無任何侵入。除了性能和對代碼的侵入性上 SkyWaking 表現不錯外,它還有如下優點幾個優點:

  • 對多語言的支持,組件豐富:目前其支持 Java、 .Net Core、PHP、NodeJS、Golang、LUA 語言,組件上也支持dubbo, mysql 等常見組件,大部分能知足咱們的需求。

  • 擴展性:對於不知足的插件,咱們按照 SkyWalking 的規則手動寫一個便可,新實現的插件對代碼無入侵。

以上雖然主要以SkyWalking爲例來介紹鏈路追蹤系統,可是並非說其餘鏈路追蹤系統一點不適用。具體選擇什麼樣的,你們可按實際場景靈活選擇。

做者:猿話 

來源:https://www.toutiao.com/i6884571378981274123/


若是您以爲這篇文章對您有點用的話,麻煩您爲本文來個四連:轉發分享、點贊、點在看、留言,由於這將是我寫做與分享更多優質文章的最強動力!


本公衆號所有博文已整理成一個目錄,請在公衆號後臺回覆「 m」獲取!

 

推薦閱讀:

一、 成爲架構師,必須掌握 10 種常見的架構模式!
二、 程序員必知的 7 種軟件架構模式
三、 一文讀懂「分佈式架構」
四、 Linux 經典的幾款收包引擎
五、 最全 VxLAN 知識詳解
六、 什麼是堡壘機?爲何須要堡壘機?

關注微信公衆號「 傑哥的IT之旅」,後臺回覆「 1024」查看更多內容,回覆「 加羣備註:地區-職業方向-暱稱 便可加入讀者交流羣。

 
  
 
  

點個[在看],是對傑哥最大的支持!

本文分享自微信公衆號 - 傑哥的IT之旅(Jake_Internet)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索