日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

作 者:碼海

原文鏈接:https://mp.weixin.qq.com/s/U-8ttlVCfYtjEPOWKBHONA

前言

在微服務架構中,一次請求往往涉及到多個模塊,多個中間件,多臺機器的相互協作才能完成。這一系列調用請求中,有些是串行的,有些是并行的,那么如何確定這個請求背后調用了哪些應用,哪些模塊,哪些節點及調用的先后順序?如何定位每個模塊的性能問題?本文將為你揭曉答案。

本文將會從以下幾個方面來闡述

  • 分布式追蹤系統原理及作用
  • SkyWalking的原理及架構設計
  • 我司在分布式調用鏈上的實踐

分布式追蹤系統的原理及作用

如何衡量一個接口的性能好壞,一般我們至少會關注以下三個指標

  • 接口的 RT 你怎么知道?
  • 是否有異常響應?
  • 主要慢在哪里?

單體架構

在初期,公司剛起步的時候,可能多會采用如下單體架構,對于單體架構我們該用什么方式來計算以上三個指標呢?

40張圖看懂分布式追蹤系統原理及實踐

 

最容易想到的顯然是用 AOP

40張圖看懂分布式追蹤系統原理及實踐

 

使用 AOP 在調用具體的業務邏輯前后分別打印一下時間即可計算出整體的調用時間,使用 AOP 來 catch 住異常也可知道是哪里的調用導致的異常。

微服務架構

在單體架構中由于所有的服務,組件都在一臺機器上,所以相對來說這些監控指標比較容易實現,不過隨著業務的快速發展,單體架構必然會朝微服務架構發展,如下

40張圖看懂分布式追蹤系統原理及實踐

 

如圖示:一個稍微復雜的微服務架構

如果有用戶反饋某個頁面很慢,我們知道這個頁面的請求調用鏈是 A -----> C -----> B -----> D,此時如何定位可能是哪個模塊引起的問題。每個服務 Service A,B,C,D 都有好幾臺機器。怎么知道某個請求調用了服務的具體哪臺機器呢?

40張圖看懂分布式追蹤系統原理及實踐

 

可以明顯看到,由于無法準確定位每個請求經過的確切路徑,在微服務這種架構下有以下幾個痛點

  1. 排查問題難度大,周期長
  2. 特定場景難復現
  3. 系統性能瓶頸分析較難

分布式調用鏈就是為了解決以上幾個問題而生,它主要的作用如下

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

通過分布式追蹤系統能很好地定位如下請求的每條具體請求鏈路,從而輕易地實現請求鏈路追蹤,每個模塊的性能瓶頸定位與分析。

40張圖看懂分布式追蹤系統原理及實踐

 


分布式調用鏈標準 - OpenTracing

知道了分布式調用鏈的作用,那我們來看下如何實現分布式調用鏈的實現及原理, 首先為了解決不同的分布式追蹤系統 API 不兼容的問題,誕生了 OpenTracing 規范,OpenTracing 是一個輕量級的標準化層,它位于應用程序/類庫和追蹤或日志分析程序之間。

40張圖看懂分布式追蹤系統原理及實踐

 

這樣 OpenTracing 通過提供平臺無關,廠商無關的 API,使得開發人員能夠方便地添加追蹤系統的實現。

說到這大家是否想過 JAVA 中類似的實現?還記得 JDBC 吧,通過提供一套標準的接口讓各個廠商去實現,程序員即可面對接口編程,不用關心具體的實現。這里的接口其實就是標準,所以制定一套標準非常重要,可以實現組件的可插拔。

40張圖看懂分布式追蹤系統原理及實踐

 

接下來我們來看 OpenTracing 的數據模型,主要有以下三個

  • Trace:一個完整請求鏈路
  • Span:一次調用過程(需要有開始時間和結束時間)
  • SpanContext:Trace 的全局上下文信息, 如里面有traceId

理解這三個概念非常重要,為了讓大家更好地理解這三個概念,我特意畫了一張圖

40張圖看懂分布式追蹤系統原理及實踐

 

如圖示,一次下單的完整請求完整就是一個 Trace, 顯然對于這個請求來說,必須要有一個全局標識來標識這一個請求,每一次調用就稱為一個 Span,每一次調用都要帶上全局的 TraceId, 這樣才可把全局 TraceId 與每個調用關聯起來,這個 TraceId 就是通過 SpanContext 傳輸的,既然要傳輸顯然都要遵循協議來調用。如圖示,我們把傳輸協議比作車,把 SpanContext 比作貨,把 Span 比作路應該會更好理解一些。

理解了這三個概念,接下來我看看分布式追蹤系統如何采集統一圖中的微服務調用鏈

40張圖看懂分布式追蹤系統原理及實踐

 

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

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

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

40張圖看懂分布式追蹤系統原理及實踐

 

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

40張圖看懂分布式追蹤系統原理及實踐

 

于是一個完整的分布式追蹤系統就實現了。

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

  1. 怎么自動采集 span 數據:自動采集,對業務代碼無侵入
  2. 如何跨進程傳遞 context
  3. traceId 如何保證全局唯一
  4. 請求量這么多采集會不會影響性能

接下我來看看 SkyWalking 是如何解決以上四個問題的

SkyWalking的原理及架構設計

怎么自動采集 span 數據

SkyWalking 采用了插件化 + javaagent 的形式來實現了 span 數據的自動采集,這樣可以做到對代碼的 無侵入性,插件化意味著可插拔,擴展性好(后文會介紹如何定義自己的插件)

40張圖看懂分布式追蹤系統原理及實踐

 


如何跨進程傳遞 context

我們知道數據一般分為 header 和 body, 就像 http 有 header 和 body, RocketMQ 也有 MessageHeader,Message Body, body 一般放著業務數據,所以不宜在 body 中傳遞 context,應該在 header 中傳遞 context,如圖示

40張圖看懂分布式追蹤系統原理及實踐

 

dubbo 中的 attachment 就相當于 header ,所以我們把 context 放在 attachment 中,這樣就解決了 context 的傳遞問題。

40張圖看懂分布式追蹤系統原理及實踐

 

小提示:這里的傳遞 context 流程均是在 dubbo plugin 處理的,業務無感知,這個 plugin 是怎么實現的呢,下文會分析

traceId 如何保證全局唯一

要保證全局唯一 ,我們可以采用分布式或者本地生成的 ID,使用分布式話需要有一個發號器,每次請求都要先請求一下發號器,會有一次網絡調用的開銷,所以 SkyWalking 最終采用了本地生成 ID 的方式,它采用了大名鼎鼎的 snowflow 算法,性能很高。

40張圖看懂分布式追蹤系統原理及實踐

 


圖示: snowflake 算法生成的 id

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

40張圖看懂分布式追蹤系統原理及實踐

 

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

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

請求量這么多,全部采集會不會影響性能?

如果對每個請求調用都采集,那毫無疑問數據量會非常大,但反過來想一下,是否真的有必要對每個請求都采集呢,其實沒有必要,我們可以設置采樣頻率,只采樣部分數據,SkyWalking 默認設置了 3 秒采樣 3 次,其余請求不采樣,如圖示

40張圖看懂分布式追蹤系統原理及實踐

 

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

40張圖看懂分布式追蹤系統原理及實踐

 

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

40張圖看懂分布式追蹤系統原理及實踐

 

這樣的話就會導致某些調用在服務 A 上被采樣了,在服務 B,C 上不被采樣,也就沒法分析調用鏈的性能,那么 SkyWalking 是如何解決的呢。

它是這樣解決的:如果上游有攜帶 Context 過來(說明上游采樣了),則下游強制采集數據。這樣可以保證鏈路完整。

SkyWalking 的基礎架構

SkyWalking 的基礎如下架構,可以說幾乎所有的的分布式調用都是由以下幾個組件組成的

40張圖看懂分布式追蹤系統原理及實踐

 

首先當然是節點數據的定時采樣,采樣后將數據定時上報,將其存儲到 ES, MySQL 等持久化層,有了數據自然而然可根據數據做可視化分析。


SkyWalking 的性能如何

接下來大家肯定比較關心 SkyWalking 的性能,那我們來看下官方的測評數據

40張圖看懂分布式追蹤系統原理及實踐

 

圖中藍色代表未使用 SkyWalking 的表現,橙色代表使用了 SkyWalking 的表現,以上是在 TPS 為 5000 的情況下測出的數據,可以看出,不論是 CPU,內存,還是響應時間,使用 SkyWalking 帶來的性能損耗幾乎可以忽略不計。

接下來我們再來看 SkyWalking 與另一款業界比較知名的分布式追蹤工具 Zipkin, Pinpoint 的對比(在采樣率為 1 秒 1 個,線程數 500,請求總數為 5000 的情況下做的對比),可以看到在關鍵的響應時間上, Zipkin(117ms),PinPoint(201ms)遠遜色于 SkyWalking(22ms)!

40張圖看懂分布式追蹤系統原理及實踐

 

從性能損耗這個指標上看,SkyWalking 完勝!

再看下另一個指標:對代碼的侵入性如何,ZipKin 是需要在應用程序中埋點的,對代碼的侵入強,而 SkyWalking 采用 javaagent + 插件化這種修改字節碼的方式可以做到對代碼無任何侵入,除了性能和對代碼的侵入性上 SkyWaking 表現不錯外,它還有以下優勢幾個優勢

  • 對多語言的支持,組件豐富:目前其支持 Java, .Net Core, php, NodeJS, Golang, LUA 語言,組件上也支持dubbo, mysql 等常見組件,大部分能滿足我們的需求。
  • 擴展性:對于不滿足的插件,我們按照 SkyWalking 的規則手動寫一個即可,新實現的插件對代碼無入侵。

我司在分布式調用鏈上的實踐

SkyWalking 在我司的應用架構

由上文可知 SkyWalking 有很多優點,那么是不是我們用了它的全部組件了呢,其實不然,來看下其在我司的應用架構

40張圖看懂分布式追蹤系統原理及實踐

 

從圖中可以看出我們只采用了 SkyWalking 的 agent 來進行采樣,放棄了另外的「數據上報及分析」,「數據存儲」,「數據可視化」三大組件,那為啥不直接采用 SkyWalking 的整套解決方案呢,因為在接入 SkyWalking 之前我們的 Marvin 監控生態體系已經相對比較完善了,如果把其整個替換成 SkyWalking,一來沒有必要,Marvin 在大多數場景下都能滿足我們的需求,二來系統替換成本高,三來如果重新接入用戶學習成本很高。

這也給我們一個啟示:任何產品搶占先機很重要,后續產品的替換成本會很高,搶占先機,也就是搶占了用戶的心智,這就像微信雖然 UI,功能上制作精良,但在國外照樣干不過 WhatsApp 一樣,因為先機已經沒了。

從另一方面來看,對架構來說,沒有最好的,只有最合適的,結合當前業務場景去平衡折中才是架構設計的本質

我司對 SkyWalking 作了哪些改造和實踐

我司主要作了以下改造和實踐

  1. 預發環境由于調試需要強制采樣
  2. 實現更細粒度的采樣?
  3. 日志中嵌入traceId
  4. 自研實現了 SkyWalking 插件

預發環境由于調試需要強制采樣

從上文分析可知 Collector 是在后臺定時采樣的,這不挺好的嗎,為啥要實現強制采樣呢。還是為了排查定位問題,有時線上出現問題,我們希望在預發上能重現,希望能看到這個請求的完整調用鏈,所以在預發上實現強制采樣很有必要。所以我們對 Skywalking 的 dubbo 插件進行了改造,實現強制采樣

我們在請求的 Cookie 上帶上一個類似 force_flag = true 這樣的鍵值對來表示我們希望強制采樣,在網關收到這個 Cookie 后,就會在 dubbo 的 attachment 里帶上force_flag = true 這個鍵值對,然后 skywalking 的 dubbo 插件就可以據此來判斷是否是強制采樣了,如果有這個值即強制采樣,如果沒有這個值,則走正常的定時采樣。

40張圖看懂分布式追蹤系統原理及實踐

 

實現更細粒度的采樣?

哈叫更細粒度的采樣。先來看下 skywalking 默認的采樣方式 ,即統一采樣

40張圖看懂分布式追蹤系統原理及實踐

 

我們知道這種方式默認是 3 秒采樣前 3 次,其他請求都丟棄,這樣的話有個問題,假設在這臺機器上在 3 秒內有多個 dubbo,mysql,redis 調用,但在如果前三次都是 dubbo 調用的話,其他像 mysql, redis 等調用就采樣不到了,所以我們對 skywalking 進行了改造,實現了分組采樣,如下

40張圖看懂分布式追蹤系統原理及實踐

 

就是說 3 秒內進行 3 次 redis, dubbo, mysql 等的采樣,也就避免了此問題

日志中如何嵌入traceId?

輸出日志中嵌入 traceId 便于我們排查問題,所以打出出 traceId 非常有必要,該怎么在日志中嵌入 traceId 呢?我們用的是 log4j,這里就要了解一下 log4j 的插件機制了,log4j 允許我們自定義插件來輸出日志的格式,首先我們需要定義日志的格式,在自定義的日志格式中嵌入 %traceId, 作為占位符,如下

40張圖看懂分布式追蹤系統原理及實踐

 

然后我們再實現一個 log4j 的插件,如下

40張圖看懂分布式追蹤系統原理及實踐

 

首先 log4j 的插件要定義一個類,這個類要繼承 LogEventPatternConverter 這個類,并且用標準 Plugin 將其自身聲明為 Plugin,通過 @ConverterKeys 這個注解指定了要替換的占位符,然后在 format 方法里將其替換掉。這樣在日志中就會出現我們想要的 TraceId ,如下

40張圖看懂分布式追蹤系統原理及實踐

 

我司自研了哪些 skywalking 插件

SkyWalking 實現了很多插件,不過未提供 memcached 和 druid 的插件,所以我們根據其規范自研了這兩者的插件

40張圖看懂分布式追蹤系統原理及實踐

 

插件如何實現呢,可以看到它主要由三個部分組成

  1. 插件定義類: 指定插件的定義類,最終會根據這里的定義類打包生成 plugin
  2. Instrumentation: 指定切面,切點,要對哪個類的哪個方法進行增強
  3. Interceptor,指定步驟 2 重要在方法的前置,后置還是異常中寫增強邏輯

可能大家看了還是不懂,那我們以 dubbo plugin 來簡單講解一下,我們知道在 dubbo 服務中,每個請求從 netty 接收到消息,遞交給業務線程池處理開始,到真正調用到業務方法結束,中間經過了十幾個 Filter 的處理

40張圖看懂分布式追蹤系統原理及實踐

 

而 MonitorFilter 可以攔截所有客戶端發出請求或者服務端處理請求,所以我們可以對 MonitorFilter 作增強,在其調用 invoke 方法前,將全局 traceId 注入到其 Invocation 的 attachment 中,這樣就可以確保在請求到達真正的業務邏輯前就已經存在全局 traceId。

所以顯然我們需要在插件中指定我們要增強的類(MonitorFilter),對其方法(invoke)做增強,要對這個方法做哪些增強呢,這就是攔截器(Inteceptor)要做的事,來看看 Dubbo 插件中的 instrumentation(DubboInstrumentation)

40張圖看懂分布式追蹤系統原理及實踐

 

我們再看看下代碼中描寫的攔截器(Inteceptor)干了什么事,以下列出關鍵步驟

40張圖看懂分布式追蹤系統原理及實踐

 

首先 beforeMethod 代表在執行 MonitorFilter 的 invoke 方法前會調用這里的方法,與之對應的是 afterMethod,代表在執行 invoke 方法后作增強邏輯。

其次我們從第 2,3點可以看到,不管是 consumer 還是 provider, 都對其全局 ID 作了相應處理,這樣確保到達真正的業務層的時候保證有了此全局 traceid,定義好 Instrumentation 和 Interceptor 后,最后一步就是在 skywalking.def 里指定定義的類

// skywalking-plugin.def 文件
dubbo=org.Apache.skywalking.apm.plugin.asf.dubbo.DubboInstrumentation

這樣打包出來的插件就會對 MonitorFilter 的 invoke 方法進行增強,在 invoke 方法執行前對期 attachment 作注入全局 traceId 等操作,這一切都是靜默的,對代碼無侵入的。

總結

本文由淺入深地介紹了分布式追蹤系統的原理,相信大家對其作用及工作機制有了比較深的理解,特別需要注意的是,引入某項技巧,一定要結合現有的技術架構作出最合理的選擇,就像 SkyWalking 有四個模塊,我司只采用其 agent 采樣功能一樣,沒有最好的技術,只有最合適的技術,通過此文,相信大家應該對 SkyWalking 的實現機制有了比較清晰的認識,文中只是介紹了一下 SkyWalking 的插件實現方式,不過其畢竟是工業級軟件,要了解其博大精深,還要多讀源碼哦。

分享到:
標簽:分布式
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定