分布式服務調用鏈路追蹤——方案選型


 

前言

目前大多數分布式追蹤系統的思想模型都來自 Google's Dapper 論文。

全鏈路追蹤工具一覽:

  • Drapper(google--未開源):最早的APM;
  • 鷹眼(阿里--未開源):
  • CAT(大眾點評--開源):跨服務的跟蹤功能與點評內部的RPC框架集成,這部分未開源且項目在2014.1已經停止維護。服務粒度的監控,通過代碼埋點的方式來實現監控,比如: 攔截器,注解,過濾器等,對代碼的侵入性較大,集成成本較高;
  • Hydra(京東):與dubbo框架集成,對於服務級別的跟蹤統計,現有業務可以無縫接入。對於細粒度的興趣點,需要業務人員手動添加.開源項目已於2013年6月停止維護;
  • PinPoint(naver--開源):字節碼探針技術,代碼無侵入,體系完善不易修改,支持java,技術棧支持dubbo.其他語言社區支援中;
  • Zipkin(Twitter--開源):方便集成於spring cloud sleuth,社區支持的插件也包括dubbo,rabbit,mysql,httpclient等,同時支持php,go,js等語言客戶端,界面功能較為簡單,本身無告警功能,可能需要二次開發。代碼入侵度小;
  • Uber-jaeger:Jaeger支持java/c++/go/node/php,在界面上較為完善(對比zipkin),但是也無告警功能。代碼入侵度小。dubbo目前無插件支持,可二次開發;
  • Skywalking(華為--開源):類似於PinPoint,目前還在apache孵化中,網上吞吐量對比中強於pinpoint,實際未驗證。本身支持dubbo;

全鏈路追蹤的核心思想:

  • 為每條請求都單獨分配一個唯一的 traceId 用來標識一條請求鏈路,該 traceId 會貫穿整個請求處理過程的所有服務。
  • 每個服務/線程都擁有自己的 spanId 標識,代表請求的其中一段處理步驟。
  • 一個請求包含一個 traceId 和一個或多個 spanId。

本文重點關注以下三種 APM 組件:

  • Zipkin:由Twitter公司開源的調用鏈分析工具,目前基於springcloud sleuth得到了廣泛的使用,特點是輕量,使用部署簡單。
  • Pinpoint:一款對Java編寫的大規模分布式系統的APM工具,由韓國人開源的分布式跟蹤組件,特點是支持多種插件,UI功能強大,接入端無代碼侵入。
  • Skywalking:是本土開源的基於字節碼注入的調用鏈分析,以及應用監控分析工具。特點是支持多種插件,UI功能較強,接入端無代碼侵入。目前已加入Apache孵化器。

 

1. 方案比較

主要從以下幾個維度來對比三種組件:

  • 探針的性能

    主要是agent對服務的吞吐量、CPU和內存的影響。微服務的規模和動態性使得數據收集的成本大幅度提高。

  • 對應用的入侵性

    對應用是否有入侵性。

  • collector的可擴展性

    能夠水平擴展以便支持大規模服務器集群。

  • 全面的調用鏈路數據分析

    提供代碼級別的可見性以便輕松定位失敗點和瓶頸。

  • 對於開發透明,容易開關

    添加新功能而無需修改代碼,容易啟用或者禁用。

  • 完整的調用鏈應用拓撲

    自動檢測應用拓撲,幫助你搞清楚應用的架構。

 

1.1 探針的性能

摘自:https://juejin.im/post/5a7a9e0af265da4e914b46f1

比較關注探針的性能,畢竟 APM 定位還是工具,如果啟用了鏈路監控組件后,直接導致吞吐量降低過半,那也是不能接受的。

對 skywalking、zipkin、pinpoint 進行了壓測,並與基線(未使用探針)的情況進行了對比。

選用了一個常見的基於 Spring 的應用程序,包含 Spring Boot, Spring MVC,redis客戶端,mysql。監控這個應用程序,每個trace,探針會抓取5個span(1 Tomcat, 1 SpringMVC, 2 Jedis, 1 Mysql)。

這邊基本和 skywalkingtest 的測試應用差不多。

模擬了三種並發用戶:500,750,1000。使用jmeter測試,每個線程發送30個請求,設置思考時間為10ms。使用的采樣率為1,即100%,這邊與生產可能有差別。

pinpoint默認的采樣率為20,即50%,通過設置agent的配置文件改為100%。zipkin默認也是1。組合起來,一共有12種。下面看下匯總表:

從上表可以看出,在三種鏈路監控組件中,skywalking 的探針對吞吐量的影響最小,zipkin的吞吐量居中。pinpoint 的探針對吞吐量的影響較為明顯,在500並發用戶時,

測試服務的吞吐量從1385降低到774,影響很大。然后再看下CPU和memory的影響,在內部服務器進行的壓測,對CPU和memory的影響都差不多在10%之內。

 

1.2 對應用的入侵性

  • zipkin

 沒有采用javaagent方式,應用強依賴ZipKin,必須打包到應用中與應用一起運行,每個項目需要添加依賴項、配置,不同探針有不同的bean配置需求;

  • skywalking

采用javaagent方式,普通功能對應用無侵入,以下兩項功能需要應用稍作修改:

    • 中添加自定義Tag項:應用代碼在SkyWalking Span中添加自定義Tag,可以按需輸出方法參數值等關鍵信息,輔助應用排錯和性能分析,PinPointZipKin都不支持(可自行實現);
    • 日志中輸出全局跟蹤ID,需要添加SkyWalking依賴項;
  • pinpoint

采用javaagent方式,對應用完全無侵入,項目無需添加任何額外依賴項,無需修改代碼,這點做得最好;

 

1.3 collector的可擴展性

collector的可擴展性,使得能夠水平擴展以便支持大規模服務器集群。

  • zipkin

開發 zipkin-Server(其實就是提供的開箱即用包),zipkin-agent 與 zipkin-Server 通過 http 或者 mq 進行通信,http 通信會對正常的訪問造成影響,

所以還是推薦基於mq異步方式通信,zipkin-Server 通過訂閱具體的 topic 進行消費。這個當然是可以擴展的,多個 zipkin-Server 實例進行異步消費 mq 中的監控信息。

  • skywalking

skywalking的collector支持兩種部署方式:單機和集群模式。collector與agent之間的通信使用了gRPC

當你使用-javaagent參數激活sky-walking的探針, 如果當前上下文中存在traceid,logback將在輸出traceId

如果探針沒有被激活,將輸出TID: N/A.而且SkyWalking是基於字節碼增強的,traceId的傳遞依賴於SkyWalking的服務端,

如果服務端異常等客戶端連接不上服務端的情況,就會出現TID: [Ignored Trace]的情況,就會丟失traceId。

  • pinpoint

pinpoint也是支持集群和單機部署的。pinpoint agent通過thrift通信框架,發送鏈路信息到collector。

 

1.4 全面的調用鏈路數據分析

全面的調用鏈路數據分析,提供代碼級別的可見性以便輕松定位失敗點和瓶頸。

  • zipkin

zipkin 的鏈路監控粒度相對沒有那么細,從下圖可以看到調用鏈中具體到接口級別,再進一步的調用信息並未涉及。

  • skywalking

skywalking 支持20+的中間件、框架、類庫,比如:主流的dubbo、Okhttp,還有DB和消息中間件。

下圖skywalking鏈路調用分析截取的比較簡單,網關調用user服務,由於支持眾多的中間件,所以skywalking鏈路調用分析比zipkin完備些。

  • pinpoint

pinpoint應該是這三種APM組件中,數據分析最為完備的組件。提供代碼級別的可見性以便輕松定位失敗點和瓶頸,下圖可以看到對於執行的sql語句,都進行了記錄。

還可以配置報警規則等,設置每個應用對應的負責人,根據配置的規則報警,支持的中間件和框架也比較完備。

 

1.5 對於開發透明,容易開關

對於開發透明,容易開關,添加新功能而無需修改代碼,容易啟用或者禁用。我們期望功能可以不修改代碼就工作並希望得到代碼級別的可見性。

對於這一點,Zipkin 使用修改過的類庫和它自己的容器(Finagle)來提供分布式事務跟蹤的功能。但是,它要求在需要時修改代碼。

skywalking和pinpoint都是基於字節碼增強的方式,開發人員不需要修改代碼,並且可以收集到更多精確的數據因為有字節碼中的更多信息。

 

1.6 完整的調用鏈應用拓撲

自動檢測應用拓撲,幫助你搞清楚應用的架構。

下面三幅圖,分別展示了APM 組件各自的調用拓撲,都能實現完整的調用鏈應用拓撲。相對來說,pinpoint 界面顯示的更加豐富,具體到調用的DB名,zipkin的拓撲局限於服務於服務之間。

  • zipkin

  • skywalking

  • pingpoint

1.7 Pinpoint與Zipkin細化比較

  • Pinpoint與Zipkin差異性

1、Pinpoint 是一個完整的性能監控解決方案:有從探針、收集器、存儲到 Web 界面等全套體系;而 Zipkin 只側重收集器和存儲服務,雖然也有用戶界面,但其功能與 Pinpoint 不可同日而語。

      反而 Zipkin 提供有 Query 接口,更強大的用戶界面和系統集成能力,可以基於該接口二次開發實現。

2、Zipkin 官方提供有基於 Finagle 框架(Scala 語言)的接口,而其他框架的接口由社區貢獻,目前可以支持 Java、Scala、Node、Go、Python、Ruby 和 C# 等主流開發語言和框架;

      但是 Pinpoint 目前只有官方提供的 Java Agent 探針,其他的都在請求社區支援中(請參見 #1759 和 #1760)。

3、Pinpoint 提供有 Java Agent 探針,通過字節碼注入的方式實現調用攔截和數據收集,可以做到真正的代碼無侵入,只需要在啟動服務器的時候添加一些參數,就可以完成探針的部署;

      而 Zipkin 的 Java 接口實現 Brave,只提供了基本的操作 API,如果需要與框架或者項目集成的話,就需要手動添加配置文件或增加代碼。

4、Pinpoint 的后端存儲基於 HBase,而 Zipkin 基於 Cassandra。

  • Pinpoint 與 Zipkin 相似性

Pinpoint 與 Zipkin 都是基於 Google Dapper 的那篇論文,因此理論基礎大致相同。兩者都是將服務調用拆分成若干有級聯關系的 Span,通過 SpanId 和 ParentSpanId 來進行調用關系的級聯;

最后再將整個調用鏈流經的所有的 Span 匯聚成一個 Trace,報告給服務端的 collector 進行收集和存儲。

即便在這一點上,Pinpoint 所采用的概念也不完全與那篇論文一致。比如他采用 TransactionId 來取代 TraceId,而真正的 TraceId 是一個結構,里面包含了 TransactionId, SpanId 和 ParentSpanId。

而且 Pinpoint 在 Span 下面又增加了一個 SpanEvent 結構,用來記錄一個 Span 內部的調用細節(比如具體的方法調用等等),因此 Pinpoint 默認會比 Zipkin 記錄更多的跟蹤數據。

但是理論上並沒有限定 Span 的粒度大小,所以一個服務調用可以是一個 Span,那么每個服務中的方法調用也可以是個 Span,

這樣的話,其實 Brave 也可以跟蹤到方法調用級別,只是具體實現並沒有這樣做而已。

  • 字節碼注入 vs API 調用

Pinpoint 實現了基於字節碼注入的 Java Agent 探針,而 Zipkin 的 Brave 框架僅僅提供了應用層面的 API,但是細想問題遠不那么簡單。

字節碼注入是一種簡單粗暴的解決方案,理論上來說無論任何方法調用,都可以通過注入代碼的方式實現攔截,也就是說沒有實現不了的,只有不會實現的。

但 Brave 則不同,其提供的應用層面的 API 還需要框架底層驅動的支持,才能實現攔截。

比如,MySQL 的 JDBC 驅動,就提供有注入 interceptor 的方法,因此只需要實現 StatementInterceptor 接口,並在 Connection String 中進行配置,就可以很簡單的實現相關攔截;

而與此相對的,低版本的 MongoDB 的驅動或者是 Spring Data MongoDB 的實現就沒有如此接口,想要實現攔截查詢語句的功能,就比較困難。

因此在這一點上,Brave 是硬傷,無論使用字節碼注入多么困難,但至少也是可以實現的,

但是 Brave 卻有無從下手的可能,而且是否可以注入,能夠多大程度上注入,更多的取決於框架的 API 而不是自身的能力。

  • 難度及成本

經過簡單閱讀 Pinpoint 和 Brave 插件的代碼,可以發現兩者的實現難度有天壤之別。在都沒有任何開發文檔支撐的前提下,Brave 比 Pinpoint 更容易上手。

Brave 的代碼量很少,核心功能都集中在 brave-core 這個模塊下,一個中等水平的開發人員,可以在一天之內讀懂其內容,並且能對 API 的結構有非常清晰的認識。

Pinpoint 的代碼封裝也是非常好的,尤其是針對字節碼注入的上層 API 的封裝非常出色,但是這依然要求閱讀人員對字節碼注入多少有一些了解,

雖然其用於注入代碼的核心 API 並不多,但要想了解透徹,恐怕還得深入 Agent 的相關代碼,

比如很難一目了然的理解 addInterceptor 和 addScopedInterceptor 的區別,而這兩個方法就是位於 Agent 的有關類型中。

因為 Brave 的注入需要依賴底層框架提供相關接口,因此並不需要對框架有一個全面的了解,只需要知道能在什么地方注入,能夠在注入的時候取得什么數據就可以了。

就像上面的例子,我們根本不需要知道 MySQL 的 JDBC Driver 是如何實現的也可以做到攔截 SQL 的能力。但是 Pinpoint 就不然,因為 Pinpoint 幾乎可以在任何地方注入任何代碼,

這需要開發人員對所需注入的庫的代碼實現有非常深入的了解,通過查看其 MySQL 和 Http Client 插件的實現就可以洞察這一點,

當然這也從另外一個層面說明 Pinpoint 的能力確實可以非常強大,而且其默認實現的很多插件已經做到了非常細粒度的攔截。

針對底層框架沒有公開 API 的時候,其實 Brave 也並不完全無計可施,我們可以采取 AOP 的方式,一樣能夠將相關攔截注入到指定的代碼中,

而且顯然 AOP 的應用要比字節碼注入簡單很多。

以上這些直接關系到實現一個監控的成本,在 Pinpoint 的官方技術文檔中,給出了一個參考數據。如果對一個系統集成的話,那么用於開發 Pinpoint 插件的成本是 100,將此插件集成入系統的成本是 0;

但對於 Brave,插件開發的成本只有 20,而集成成本是 10。從這一點上可以看出官方給出的成本參考數據是 5:1。

但是官方又強調了,如果有 10 個系統需要集成的話,那么總成本就是 10 * 10 + 20 = 120,就超出了 Pinpoint 的開發成本 100,而且需要集成的服務越多,這個差距就越大。

  • 通用性和擴展性

很顯然,這一點上 Pinpoint 完全處於劣勢,從社區所開發出來的集成接口就可見一斑。

Pinpoint 的數據接口缺乏文檔,而且也不太標准(參考論壇討論帖),需要閱讀很多代碼才可能實現一個自己的探針(比如 Node 的或者 PHP 的)。

而且團隊為了性能考慮使用了 Thrift 作為數據傳輸協議標准,比起 HTTP 和 JSON 而言難度增加了不少。

  • 社區支持

這一點也不必多說,Zipkin 由 Twitter 開發,可以算得上是明星團隊,而 Naver 的團隊只是一個默默無聞的小團隊(從 #1759 的討論中可以看出)。

雖然說這個項目在短期內不太可能消失或停止更新,但畢竟不如前者用起來更加放心。

而且沒有更多社區開發出來的插件,讓 Pinpoint 只依靠團隊自身的力量完成諸多框架的集成實屬困難,而且他們目前的工作重點依然是在提升性能和穩定性上。

  • 其他

Pinpoint 在實現之初就考慮到了性能問題,www.naver.com 網站的后端某些服務每天要處理超過 200 億次的請求,因此他們會選擇 Thrift 的二進制變長編碼格式、

而且使用 UDP 作為傳輸鏈路,同時在傳遞常量的時候也盡量使用數據參考字典,傳遞一個數字而不是直接傳遞字符串等等。

這些優化也增加了系統的復雜度:包括使用 Thrift 接口的難度、UDP 數據傳輸的問題、以及數據常量字典的注冊問題等等。

相比之下,Zipkin 使用熟悉的 Restful 接口加 JSON,幾乎沒有任何學習成本和集成難度,只要知道數據傳輸結構,就可以輕易的為一個新的框架開發出相應的接口。

另外 Pinpoint 缺乏針對請求的采樣能力,顯然在大流量的生產環境下,不太可能將所有的請求全部記錄,這就要求對請求進行采樣,以決定什么樣的請求是我需要記錄的。

Pinpoint 和 Brave 都支持采樣百分比,也就是百分之多少的請求會被記錄下來。但是,除此之外 Brave 還提供了 Sampler 接口,可以自定義采樣策略,尤其是當進行 A/B 測試的時候,這樣的功能就非常有意義了。

  • 總結

從短期目標來看,Pinpoint 確實具有壓倒性的優勢:無需對項目代碼進行任何改動就可以部署探針、追蹤數據細粒化到方法調用級別、功能強大的用戶界面以及幾乎比較全面的 Java 框架支持。

但是長遠來看,學習 Pinpoint 的開發接口,以及未來為不同的框架實現接口的成本都還是個未知數。

相反,掌握 Brave 就相對容易,而且 Zipkin 的社區更加強大,更有可能在未來開發出更多的接口。在最壞的情況下,

我們也可以自己通過 AOP 的方式添加適合於我們自己的監控代碼,而並不需要引入太多的新技術和新概念。

而且在未來業務發生變化的時候,Pinpoint 官方提供的報表是否能滿足要求也不好說,增加新的報表也會帶來不可以預測的工作難度和工作量。

 

1.8 Pinpoint與Skywalking細化比較

首先,上個別人的研究成果,我也是踩着巨人的肩膀繼續前進的。

隨着pinpoint版本的迭代更新,這圖上的結論有些已經過時了,比如pinpoint方面:

  1. 協議,最新2.2.2版本也是默認使用gRPC的;
  2. TraceId查詢,最新2.2.2版本也是支持的;
  3. 發布包,最新2.2.2版本同樣也是采用jar包部署的;
  4. 異步跟蹤執行,最新2.2.2版本也已經支持了;

接着說我們今天具體要對比的內容:

  • UI比較

pinpoint的UI看上去更加的美觀、友好、方便,pinpoint確實勝skywalking好幾分,來兩張圖,各位看官自己比較。

  • 跟蹤粒度

看完了外觀,我們再來對比下它們各自的內功,畢竟這類工具是要干活的,光當花瓶沒有用,關鍵時候得派的上用場才行。

同樣,我們先上兩張圖,來看看pinpoint和skywalking的跟蹤粒度如何。

可以看出pinpoint可以監控到每個鏈路過程的耗時情況,包括SQL執行耗時、第三方服務響應耗時等,甚至連SQL的變量參數都跟蹤出來了。

而skywalking只監控到了接口耗時,並沒有監控更多一點的鏈路耗時信息,有群友告知說skywalking能監控到方法級,但是需要侵入代碼,在每個要跟蹤的方法上面加注解,

所以我直接放棄了,因為這樣的代價實在太大了點。而且即使監控到方法級,也只能知道哪個方法慢了,方法下面可能還有數據庫調用、第三方方法調用等,還是沒法定位出真正的問題。

所以skywalking這款APM監控工具,個人理解,更多地是用來監控接口響應耗時並提出告警,至於具體的性能問題嘛,只能通過其他手段再進一步定位了。

所以,在監控粒度上面,skywalking差pinpoint不是一點半點,這是差了好幾個量級啊。

  • JVM監控

接下來我們再來對比下這類APM工具的另外一個非常好用的功能,監控JVM。

這邊就簡單羅列下它們都能監控到那些JVM指標

從上面對比結果來看,pinpoint在JVM監控方面要更強大得多,比如對Thread、Open File Descriptor、Data Source的支持,尤其是Data Source,實在是太方便了,數據庫連接池的使用情況一目了然。

而skywaling的唯一得分點,是支持GC指標的查看。

  • 性能損耗

既然pinpoint跟蹤粒度比skywalking詳細了好幾個量級,那么對應地,它的性能損耗是否要大得多呢?翻看有些網友(比如下面參考鏈接)的測試結果,

pinpoint的性能損耗可以達到50%左右,這也太恐怖了,但是根據官方宣傳,它的性能損耗是在3%以內的,那么到底誰是靠譜的呢?

本人平時都是開着APM在做壓測的,並沒有感覺會有很大的性能損耗,總體損耗應該在8%以內,並且性能測試結果指標還都蠻OK的,所以,對於性能損耗這塊,我對pinpoint還是挺有信心的。

貼個官方性能損耗說明:

  • 總結

主要從UI、跟蹤粒度、JVM監控這三個方面對pinpoint和skywalking做了個人使用體驗上的對比,從對比結果來看,pinpoint無論在操作簡便性還是性能問題定位上,還是要優勝於skywalking的。

畢竟作為一款APM工具,能夠更好更快更全面地發現性能問題,才是它們最大的價值所在。

也可能是我對skywalking了解的還太膚淺,還沒發現skywalking真正的強大和美好。各位如果持有不同看法和意見的,歡迎留言探討。

 

2. 方案總結

基本

方案

擴展性

實現方式

代碼侵入性

性能損失

傳輸協議

客戶端支持

存儲

skywalking

java探針
字節碼注入

部分侵入(生成TraceId)

gRPC Java, .NET, PHP等 es,mysql,H2,TIDB

sleuth+zipkin

攔截請求

侵入(強依賴zipkin)

Http,MQ java,c#,go,php等 es,mysql,cassandra,內存

pingpoint

java探針
字節碼注入

無侵入

Thrift,gRPC java、php hbase+mysql

分析

方案

顆粒度

調用鏈應用拓撲

UI豐富程度

告警支持 jvm監控 trace查詢

全局調用統計

skywalking

方法級 服務+中間件 支持 支持 支持 支持

sleuth+zipkin

接口級

服務 不支持 不支持 支持 不支持

pingpoint

代碼級

服務+中間件 支持 支持 支持 支持

 

 

 

引用:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM