發些存稿:)
0. APM簡介
隨着微服務架構的流行,一次請求往往需要涉及到多個服務,因此服務性能監控和排查就變得更復雜:
- 不同的服務可能由不同的團隊開發、甚至可能使用不同的編程語言來實現
- 服務有可能布在了幾千台服務器,橫跨多個不同的數據中心
因此,就需要一些可以幫助理解系統行為、用於分析性能問題的工具,以便發生故障的時候,能夠快速定位和解決問題,這就是APM系統,全稱是(Application Performance Monitor,當然也有叫 Application Performance Management tools)
AMP最早是谷歌公開的論文提到的 Google Dapper。Dapper是Google生產環境下的分布式跟蹤系統,自從Dapper發展成為一流的監控系統之后,給google的開發者和運維團隊幫了大忙,所以谷歌公開論文分享了Dapper。
1. 谷歌Dapper介紹
1.1 Dapper的挑戰
在google的首頁頁面,提交一個查詢請求后,會經歷什么:
- 可能對上百台查詢服務器發起了一個Web查詢,每一個查詢都有自己的Index
- 這個查詢可能會被發送到多個的子系統,這些子系統分別用來處理廣告、進行拼寫檢查或是查找一些像圖片、視頻或新聞這樣的特殊結果
- 根據每個子系統的查詢結果進行篩選,得到最終結果,最后匯總到頁面上
總結一下:
- 一次全局搜索有可能調用上千台服務器,涉及各種服務。
- 用戶對搜索的耗時是很敏感的,而任何一個子系統的低效都導致導致最終的搜索耗時
如果一次查詢耗時不正常,工程師怎么來排查到底是由哪個服務調用造成的?
- 首先,這個工程師可能無法准確的定位到這次全局搜索是調用了哪些服務,因為新的服務、乃至服務上的某個片段,都有可能在任何時間上過線或修改過,有可能是面向用戶功能,也有可能是一些例如針對性能或安全認證方面的功能改進
- 其次,你不能苛求這個工程師對所有參與這次全局搜索的服務都了如指掌,每一個服務都有可能是由不同的團隊開發或維護的
- 再次,這些暴露出來的服務或服務器有可能同時還被其他客戶端使用着,所以這次全局搜索的性能問題甚至有可能是由其他應用造成的
從上面可以看出Dapper需要:
- 無所不在的部署,無所不在的重要性不言而喻,因為在使用跟蹤系統的進行監控時,即便只有一小部分沒被監控到,那么人們對這個系統是不是值得信任都會產生巨大的質疑
- 持續的監控
1.2 Dapper的三個具體設計目標
-
性能消耗低
APM組件服務的影響應該做到足夠小。服務調用埋點本身會帶來性能損耗,這就需要調用跟蹤的低損耗,實際中還會通過配置采樣率的方式,選擇一部分請求去分析請求路徑。在一些高度優化過的服務,即使一點點損耗也會很容易察覺到,而且有可能迫使在線服務的部署團隊不得不將跟蹤系統關停。
-
應用透明,也就是代碼的侵入性小
即也作為業務組件,應當盡可能少入侵或者無入侵其他業務系統,對於使用方透明,減少開發人員的負擔。
對於應用的程序員來說,是不需要知道有跟蹤系統這回事的。如果一個跟蹤系統想生效,就必須需要依賴應用的開發者主動配合,那么這個跟蹤系統也太脆弱了,往往由於跟蹤系統在應用中植入代碼的bug或疏忽導致應用出問題,這樣才是無法滿足對跟蹤系統“無所不在的部署”這個需求。
-
可擴展性
一個優秀的調用跟蹤系統必須支持分布式部署,具備良好的可擴展性。能夠支持的組件越多當然越好。或者提供便捷的插件開發API,對於一些沒有監控到的組件,應用開發者也可以自行擴展。
-
數據的分析
數據的分析要快 ,分析的維度盡可能多。跟蹤系統能提供足夠快的信息反饋,就可以對生產環境下的異常狀況做出快速反應。分析的全面,能夠避免二次開發。
1.3 Dapper的分布式跟蹤原理
先來看一次請求調用示例:
- 包括:前端(A),兩個中間層(B和C),以及兩個后端(D和E)
- 當用戶發起一個請求時,首先到達前端A服務,然后分別對B服務和C服務進行RPC調用;
- B服務處理完給A做出響應,但是C服務還需要和后端的D服務和E服務交互之后再返還給A服務,最后由A服務來響應用戶的請求;
Dapper是如何來跟蹤記錄這次請求呢?
1.3.1 跟蹤樹和span
Span是dapper的基本工作單元,一次鏈路調用(可以是RPC,DB等沒有特定的限制)創建一個span,通過一個64位ID標識它;同時附加(Annotation)作為payload負載信息,用於記錄性能等數據。
上圖說明了span在一次大的跟蹤過程中是什么樣的。Dapper記錄了span名稱,以及每個span的ID和父ID,以重建在一次追蹤過程中不同span之間的關系。如果一個span沒有父ID被稱為root span。所有span都掛在一個特定的跟蹤上,也共用一個跟蹤id。
再來看下Span的細節:
Span數據結構:
type Span struct {
TraceID int64 // 用於標示一次完整的請求id
Name string
ID int64 // 當前這次調用span_id
ParentID int64 // 上層服務的調用span_id 最上層服務parent_id為null
Annotation []Annotation // 用於標記的時間戳
Debug bool
}
1.3.2 TraceID
類似於 樹結構的Span集合,表示一次完整的跟蹤,從請求到服務器開始,服務器返回response結束,跟蹤每次rpc調用的耗時,存在唯一標識trace_id。比如:你運行的分布式大數據存儲一次Trace就由你的一次請求組成。
每種顏色的note標注了一個span,一條鏈路通過TraceId唯一標識,Span標識發起的請求信息。樹節點是整個架構的基本單元,而每一個節點又是對span的引用。節點之間的連線表示的span和它的父span直接的關系。雖然span在日志文件中只是簡單的代表span的開始和結束時間,他們在整個樹形結構中卻是相對獨立的。
1.3.3 Annotation
Dapper允許應用程序開發人員在Dapper跟蹤的過程中添加額外的信息,以監控更高級別的系統行為,或幫助調試問題。這就是Annotation:
Annotation,用來記錄請求特定事件相關信息(例如時間),一個span中會有多個annotation注解描述。通常包含四個注解信息:
(1) cs:Client Start,表示客戶端發起請求
(2) sr:Server Receive,表示服務端收到請求
(3) ss:Server Send,表示服務端完成處理,並將結果發送給客戶端
(4) cr:Client Received,表示客戶端獲取到服務端返回信息
Annotation數據結構:
type Annotation struct {
Timestamp int64
Value string
Host Endpoint
Duration int32
}
1.3.4 采樣率
低損耗的是Dapper的一個關鍵的設計目標,因為如果這個工具價值未被證實但又對性能有影響的話,你可以理解服務運營人員為什么不願意部署它。
另外,某些類型的Web服務對植入帶來的性能損耗確實非常敏感。
因此,除了把Dapper的收集工作對基本組件的性能損耗限制的盡可能小之外,Dapper支持設置采樣率來減少性能損耗,同時支持可變采樣。
2. APM組件選型
市面上的全鏈路監控理論模型大多都是借鑒Google Dapper論文,重點關注以下三種APM組件:
- Zipkin:由Twitter公司開源,開放源代碼分布式的跟蹤系統,用於收集服務的定時數據,以解決微服務架構中的延遲問題,包括:數據的收集、存儲、查找和展現。
- Pinpoint:一款對Java編寫的大規模分布式系統的APM工具,由韓國人開源的分布式跟蹤組件。
- Skywalking:國產的優秀APM組件,是一個對JAVA分布式應用程序集群的業務運行情況進行追蹤、告警和分析的系統。
2.1 對比項
主要對比項:
-
探針的性能
主要是agent對服務的吞吐量、CPU和內存的影響。微服務的規模和動態性使得數據收集的成本大幅度提高。
-
collector的可擴展性
能夠水平擴展以便支持大規模服務器集群。
-
全面的調用鏈路數據分析
提供代碼級別的可見性以便輕松定位失敗點和瓶頸。
-
對於開發透明,容易開關
添加新功能而無需修改代碼,容易啟用或者禁用。
-
完整的調用鏈應用拓撲
自動檢測應用拓撲,幫助你搞清楚應用的架構
2.2 探針的性能
比較關注探針的性能,畢竟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%之內。
2.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。
-
pinpoint
同樣,pinpoint也是支持集群和單機部署的。pinpoint agent通過thrift通信框架,發送鏈路信息到collector。
2.4 全面的調用鏈路數據分析
全面的調用鏈路數據分析,提供代碼級別的可見性以便輕松定位失敗點和瓶頸。
zipkin
zipkin的鏈路監控粒度相對沒有那么細,從上圖可以看到調用鏈中具體到接口級別,再進一步的調用信息並未涉及。
skywalking
**skywalking 還支持20+的中間件、框架、類庫**,比如:主流的dubbo、Okhttp,還有DB和消息中間件。上圖skywalking鏈路調用分析截取的比較簡單,網關調用user服務,**由於支持眾多的中間件,所以skywalking鏈路調用分析比zipkin完備些**。
pinpoint
pinpoint應該是這三種APM組件中,數據分析最為完備的組件。提供代碼級別的可見性以便輕松定位失敗點和瓶頸,上圖可以看到對於執行的sql語句,都進行了記錄。還可以配置報警規則等,設置每個應用對應的負責人,根據配置的規則報警,支持的中間件和框架也比較完備。
2.5 對於開發透明,容易開關
對於開發透明,容易開關,添加新功能而無需修改代碼,容易啟用或者禁用。我們期望功能可以不修改代碼就工作並希望得到代碼級別的可見性。
對於這一點,Zipkin 使用修改過的類庫和它自己的容器(Finagle)來提供分布式事務跟蹤的功能。但是,它要求在需要時修改代碼。skywalking和pinpoint都是基於字節碼增強的方式,開發人員不需要修改代碼,並且可以收集到更多精確的數據因為有字節碼中的更多信息。
2.6 完整的調用鏈應用拓撲
自動檢測應用拓撲,幫助你搞清楚應用的架構。
zipkin鏈路拓撲:
skywalking鏈路拓撲:
三個組件都能實現完整的調用鏈應用拓撲。相對來說:
- pinpoint界面顯示的更加豐富,具體到調用的DB名
- zipkin的拓撲局限於服務於服務之間
2.7 社區支持
Zipkin 由 Twitter 開發,可以算得上是明星團隊,而 pinpoint的Naver 的團隊只是一個默默無聞的小團隊,skywalking是國內的明星項目,目前屬於apache孵化項目,社區活躍。
2.8 總結
zipkin | pinpoint | skywalking | |
---|---|---|---|
探針性能 | 中 | 低 | 高 |
collector擴展性 | 高 | 中 | 高 |
調用鏈路數據分析 | 低 | 高 | 中 |
對開發透明性 | 中 | 高 | 高 |
調用鏈應用拓撲 | 中 | 高 | 中 |
社區支持 | 高 | 中 | 高 |
相對來說,skywalking更占優,因此團隊采用skywalking作為APM工具。
3. 參考內容
本文主要內容參考下文:
https://juejin.im/post/5a7a9e0af265da4e914b46f1
http://bigbully.github.io/Dapper-translation/