用SkyWalking做分布式追蹤和應用性能監(jiān)控系統(tǒng)
SkyWalking 是觀察性分析平臺和應用性能管理系統(tǒng)。提供分布式追蹤、服務網(wǎng)格遙測分析、度量聚合和可視化一體化解決方案。
特性:
- 多種監(jiān)控手段,語言探針和service mesh
- 多語言自動探針,Java,.NET Core和Node.JS
- 輕量高效,不需要大數(shù)據(jù)
- 模塊化,UI、存儲、集群管理多種機制可選
- 支持告警
- 優(yōu)秀的可視化方案
Skywalking 技術架構

整個系統(tǒng)分為三部分:
- agent:采集tracing(調(diào)用鏈數(shù)據(jù))和metric(指標)信息并上報
- OAP:收集tracing和metric信息通過analysis core模塊將數(shù)據(jù)放入持久化容器中(ES,H2(內(nèi)存數(shù)據(jù)庫),mysql等等),并進行二次統(tǒng)計和監(jiān)控告警
- webapp:前后端分離,前端負責呈現(xiàn),并將查詢請求封裝為graphQL提交給后端,后端通過ribbon做負載均衡轉發(fā)給OAP集群,再將查詢結果渲染展示
Skywalking也提供了其他的一些特性:
- 配置重載:支持通過jvm參數(shù)覆寫默認配置,支持動態(tài)配置管理
- 集群管理:這個主要體現(xiàn)在OAP,通過集群部署分擔數(shù)據(jù)上報的流量壓力和二次計算的計算壓力,同時集群也可以通過配置切換角色,分別面向數(shù)據(jù)采集(collector)和計算(aggregator,alarm),需要注意的是agent目前不支持多collector負載均衡,而是隨機從集群中選擇一個實例進行數(shù)據(jù)上報
- 支持k8s和mesh
- 支持數(shù)據(jù)容器的擴展,例如官方主推是ES,通過擴展接口,也可以實現(xiàn)插件去- - 支持其他的數(shù)據(jù)容器
- 支持數(shù)據(jù)上報receiver的擴展,例如目前主要是支持gRPC接受agent的上報,但是也可以實現(xiàn)插件支持其他類型的數(shù)據(jù)上報(官方默認實現(xiàn)了對Zipkin,telemetry和envoy的支持)
- 支持客戶端采樣和服務端采樣,不過服務端采樣最有意義
- 官方制定了一個數(shù)據(jù)查詢腳本規(guī)范:OAL(Observability Analysis Language),語法類似Linq,以簡化數(shù)據(jù)查詢擴展的工作量
- 支持監(jiān)控預警,通過OAL獲取數(shù)據(jù)指標和閾值進行對比來觸發(fā)告警,支持webhook擴展告警方式,支持統(tǒng)計周期的自定義,以及告警靜默防止重復告警
數(shù)據(jù)容器
由于Skywalking并沒有自己定制的數(shù)據(jù)容器或者使用多種數(shù)據(jù)容器增加復雜度,而是主要使用ElasticSearch(當然開源的基本上都是這樣來保持簡潔,例如Pinpoint也只使用了HBase),所以數(shù)據(jù)容器的特性以及自己數(shù)據(jù)結構基本上就限制了業(yè)務的上限,以ES為例:
- ES查詢功能異常強大,在數(shù)據(jù)篩選方面碾壓其他所有容器,在數(shù)據(jù)篩選潛力巨大(Skywalking默認的查詢維度就比使用HBase的Pinpoint強很多)
- 支持sharding分片和replicas數(shù)據(jù)備份,在高可用/高性能/大數(shù)據(jù)支持都非常好
- 支持批量插入,高并發(fā)下的插入性能大大增強
- 數(shù)據(jù)密度低,源于ES會提前構建大量的索引來優(yōu)化搜索查詢,這是查詢功能強大和性能好的代價,但是鏈路跟蹤往往有非常多的上下文需要記錄,所以Skywalking把這些上下文二進制化然后通過Base64編碼放入data_binary字段并且將字段標記為not_analyzed來避免進行預處理建立查詢索引
總體來說,Skywalking盡量使用ES在大數(shù)據(jù)和查詢方面的優(yōu)勢,同時盡量減少ES數(shù)據(jù)密度低的劣勢帶來的影響,從目前來看,ES在調(diào)用鏈跟蹤方面是不二的數(shù)據(jù)容器,而在數(shù)據(jù)指標方面,ES也能中規(guī)中矩的完成業(yè)務,雖然和時序數(shù)據(jù)庫相比要弱一些,但在PB級以下的數(shù)據(jù)支持也不會有太大問題。
數(shù)據(jù)結構
如果說數(shù)據(jù)容器決定了上限,那么數(shù)據(jù)結構則決定了實際到達的高度。Skywalking的數(shù)據(jù)結構主要為:
- 數(shù)據(jù)維度(ES索引為skywalking_*_inventory)
- service:服務
- instance:實例
- endpoint:接口
- network_adress:外部依賴
- 數(shù)據(jù)內(nèi)容
- 原始數(shù)據(jù)
- 調(diào)用鏈跟蹤數(shù)據(jù)(調(diào)用鏈的trace信息,ES索引為skywalking_segment,Skywalking主要的數(shù)據(jù)消耗都在這里)
- 指標(主要是jvm或者envoy的運行時指標,例如ES索引skywalking_instance_jvm_cpu)
- 二次統(tǒng)計指標
- 指標(按維度/時間二次統(tǒng)計出來的例如pxx、sla等指標,例如ES索引skywalking_database_access_p75_month)
- 數(shù)據(jù)庫慢查詢記錄(數(shù)據(jù)庫索引:skywalking_top_n_database_statement)
- 關聯(lián)關系(維度/指標之間的關聯(lián)關系,ES索引為skywalking_relation)
- 特別記錄
- 告警信息(ES索引為skywalking_alarm_record)
- 并發(fā)控制(ES索引為skywalking_register_lock)
其中數(shù)量占比最大的就是調(diào)用鏈跟蹤數(shù)據(jù)和各種指標,而這些數(shù)據(jù)均可以通過OAP設置過期時間,以降低歷史數(shù)據(jù)的對磁盤占用和查詢效率的影響。
調(diào)用鏈跟蹤數(shù)據(jù)
作為Skywalking的核心數(shù)據(jù),調(diào)用鏈跟蹤數(shù)據(jù)(skywalking_segment)基本上奠定了整個系統(tǒng)的基礎,而如果要詳細的了解調(diào)用鏈跟蹤的話,就不得不提到openTracing。
openTracing基本上是目前開源調(diào)用鏈跟蹤系統(tǒng)的一個事實標準,它制定了調(diào)用鏈跟蹤的基本流程和基本的數(shù)據(jù)結構,同時也提供了各個語言的實現(xiàn)。如果用一張圖來表現(xiàn)openTracing,則是如下:

其中:
- SpanContext:一個類似于MDC(Slfj)或者ThreadLocal的組件,負責整個調(diào)用鏈數(shù)據(jù)采集過程中的上下文保持和傳遞
-
Trace:一次調(diào)用的完整記錄
- Span:一次調(diào)用中的某個節(jié)點/步驟,類似于一層堆棧信息,Trace是由多個Span組成,Span和Span之間也有父子或者并列的關系來標志這個節(jié)點/步驟在整個調(diào)用中的位置
- Tag:節(jié)點/步驟中的關鍵信息
- Log:節(jié)點/步驟中的詳細記錄,例如異常時的異常堆棧
- Baggage:和SpanContext一樣并不屬于數(shù)據(jù)結構而是一種機制,主要用于跨Span或者跨實例的上下文傳遞,Baggage的數(shù)據(jù)更多是用于運行時,而不會進行持久化
- Span:一次調(diào)用中的某個節(jié)點/步驟,類似于一層堆棧信息,Trace是由多個Span組成,Span和Span之間也有父子或者并列的關系來標志這個節(jié)點/步驟在整個調(diào)用中的位置
以一個Trace為例:

首先是外部請求調(diào)用A,然后A依次同步調(diào)用了B和C,而B被調(diào)用時會去同步調(diào)用D,C被調(diào)用的時候會依次同步調(diào)用E和F,F(xiàn)被調(diào)用的時候會通過異步調(diào)用G,G則會異步調(diào)用H,最終完成一次調(diào)用。
上圖是通過Span之間的依賴關系來表現(xiàn)一個Trace,而在時間線上,則可以有如下的表達:

當然,如果是同步調(diào)用的話,父Span的時間占用是包括子Span的時間消耗的。
而落地到Skywalking中,我們以一條skywalking_segment的記錄為例:
{
"trace_id": "52.70.15530767312125341",
"endpoint_name": "Mysql/JDBI/Connection/commit",
"latency": 0,
"end_time": 1553076731212,
"endpoint_id": 96142,
"service_instance_id": 52,
"version": 2,
"start_time": 1553076731212,
"data_binary": "CgwKCjRGnPvp5eikyxsSXhD///8BGMz62NSZLSDM+tjUmS0wju8FQChQAVgBYCF6DgoHZGIudHlwZRIDc3FsehcKC2RiLmluc3RhbmNlEghyaXNrZGF0YXoOCgxkYi5zdGF0ZW1lbnQYAiA0",
"service_id": 2,
"time_bucket": 20190320181211,
"is_error": 0,
"segment_id": "52.70.15530767312125340"
}
其中:
- trace_id:本次調(diào)用的唯一id,通過snowflake模式生成
- endpoint_name:被調(diào)用的接口
- latency:耗時
- end_time:結束時間戳
- endpoint_id:被調(diào)用的接口的唯一id
- service_instance_id:被調(diào)用的實例的唯一id
- version:本數(shù)據(jù)結構的版本號
- start_time:開始時間戳
- data_binary:里面保存了本次調(diào)用的所有Span的數(shù)據(jù),序列化并用Base64編碼,不會進行分析和用于查詢
- service_id:服務的唯一id
- time_bucket:調(diào)用所處的時段
- is_error:是否失敗
- segment_id:數(shù)據(jù)本身的唯一id,類似于主鍵,通過snowflake模式生成
這里可以看到,目前Skywalking雖然相較于Pinpoint來說查詢的維度要多一些,但是也很有限,而且除了endPoint,并沒有和業(yè)務有關聯(lián)的字段,只能通過時間/服務/實例/接口/成功標志/耗時來進行非業(yè)務相關的查詢,如果后續(xù)要增強業(yè)務相關的搜索查詢的話,應該還需要增加一些用于保存動態(tài)內(nèi)容(如messageId,orderId等業(yè)務關鍵字)的字段用于快速定位
指標
指標數(shù)據(jù)相對于Tracing則要簡單得多了,一般來說就是指標標志、時間戳、指標值,而Skywalking中的指標有兩種:一種是采集的原始指標值,例如jvm的各種運行時指標(例如cpu消耗、內(nèi)存結構、GC信息等);一種是各種二次統(tǒng)計指標(例如tp性能指標、SLA等,當然也有為了便于查詢的更高時間維度的指標,例如基于分鐘、小時、天、周、月)
例如以下是索引skywalking_endpoint_cpm_hour中的一條記錄,用于標志一個小時內(nèi)某個接口的cpm指標:
{
"total": 8900,
"service_id": 5,
"time_bucket": 2019031816,
"service_instance_id": 5,
"entity_id": "7",
"value": 148
}
各個字段的釋義如下:
- total:一分鐘內(nèi)的調(diào)用總量
- service_id:所屬服務的唯一id
- time_bucket:統(tǒng)計的時段
- service_instance_id:所屬實例的唯一id
- entity_id:接口(endpoint)的唯一id
- value:cpm的指標值(cpm=call per minute,即total/60)
agent
agent(apm-sniffer)是Skywalking的Java探針實現(xiàn),主要負責:
- 采集應用實例的jvm指標
- 通過切向編程進行數(shù)據(jù)埋點,采集調(diào)用鏈數(shù)據(jù)
- 通過RPC將采集的數(shù)據(jù)上報
當然,agent還實現(xiàn)了客戶端采樣,不過在APM監(jiān)控系統(tǒng)里進行客戶端數(shù)據(jù)采樣都是沒有靈魂的,所以這里就不再贅述了。
首先,agent通過 org.apache.skywalking.apm.agent.core.boot.BootService 實現(xiàn)了整體的插件化,agent啟動會加載所有的BootService實現(xiàn),并通過 ServiceManager 來管理這些插件的生命周期,采集jvm指標、gRPC連接管理、調(diào)用鏈數(shù)據(jù)維護、數(shù)據(jù)上報OAP這些服務均是通過這種方式擴展。
然后,agent還通過bytebuddy以javaagent的模式,通過字節(jié)碼增強的機制來構造AOP環(huán)境,再提供PluginDefine的規(guī)范方便探針的開發(fā),最終實現(xiàn)非侵入性的數(shù)據(jù)埋點,采集調(diào)用鏈數(shù)據(jù)。
OAP
同agent類似,OAP作為Skywalking最核心的模塊,也實現(xiàn)了自己的擴展機制,不過在這里叫做Module,具體可以參考library-module,在module的機制下,Skywalking實現(xiàn)了自己必須核心組件:
- core:整個OAP核心業(yè)務(remoting、cluster、storage、analysis、query、alarm)的規(guī)范和接口
- cluster:集群管理的具體實現(xiàn)
- storage:數(shù)據(jù)容器的具體實現(xiàn)
- query:為前端提供的查詢接口的具體實現(xiàn)
- receiver:接收探針上報數(shù)據(jù)的接收器的具體實現(xiàn)
- alarm:監(jiān)控告警的具體實現(xiàn)
以及一個可選組件:
- telemetry:用于監(jiān)控OAP自身的健康狀況
而前面提到的OAP的高擴展性則體現(xiàn)在核心業(yè)務的規(guī)范均定義在了core中,如果有需要自己擴展的,只需要自己單獨做自己的實現(xiàn),而不需要做侵入式的改動,最典型的示例則是官方支持的storage,不僅支持單機demo的內(nèi)存數(shù)據(jù)庫H2和經(jīng)典的ES,連目前開源的Tidb都可以接入。
【轉載請注明出處】:https://blog.csdn.net/huahao1989/article/details/107117546