全鏈路根因定位,虎牙APM可觀測平臺建設實踐
隨著虎牙業務量的大規模增長,分布式應用服務架構日益復雜,排障定位變得越來越困難,原有傳統監控方式已無法跟上業務發展需要。虎牙新建設了一套APM平臺,結合虎牙直播業務特性,也緊靠業界標準做了高度自研擴展,幫助研發和運維提高工作效率,保障線上應用服務穩定運行。
本次分享將通過以下幾個部分來介紹整體思路和實踐過程:
一、項目背景
圖片
1.當時痛點
虎牙當時各團隊的應用監控方案多樣,有自建應用接口日志采集監控,也有直接使用各類開源Trace系統,這樣就導致跨團隊的鏈路無法相互打通,同時也缺乏統一的產品設計,極大地影響了整體排障效率。
2.切入點
從客戶端到后端分布式應用服務的全鏈路打通,提供透明零成本的接入方案快速覆蓋業務,對Metric/Trace/Log監控數據進行整合并分析錯誤和異常,最終做到全鏈路根因定位。
3.目標
建設APM可觀測項目落地,根據錯誤的發現、定位和影響面分析等核心指標來指導方向和衡量效果,最終幫助用戶提高排障效率。
二、方案實踐
1.設計方案思考
圖片
數據采集:接入透明零成本是用戶愿意接的關鍵
數據關聯:Metric & Trace & Log的可觀測關聯模型設計
全鏈路:客戶端 -> Nginx/信令 -> 分布式應用服務 -> 數據庫/緩存
根因定位:根據關聯模型數據的實時自動化分析來發現和定位問題
2.可觀測模型分析
圖片
根據應用服務處理請求的過程設計以下模型:
- Handle模型
描述該應用服務處理了什么請求,調用什么處理方法,使用什么資源等,包括相關Metric/Span/Log數據采集,Trace上下文隨請求處理在線程本地變量中進行透明傳遞。
- RPC模型
描述該應用服務有什么RPC、Http、數據庫、緩存等請求調用,包括相關Metric/Span/Log數據采集,Trace上下文隨請求頭在跨服務進程之間傳遞。
- 可觀測模型關聯
- 縱向:應用服務進程內、跨進程的請求調用鏈路關聯
- 橫向:隊列、線程池、連接池等資源數據和請求關聯
總結:設計包含從Handle和RPC數據采集,到縱向和橫向整體關聯的全鏈路可觀測模型,我們根據模型進一步設計了SDK和服務端的整體架構。
3.SDK架構介紹
圖片
- 零成本接入
- Java:字節碼織入技術來自動識別多種框架并埋點
- C++:集成在Taf框架埋點
- 客戶端:集成在信令SDK埋點
- 基于業界標準
基于Opentracing標準選擇了Jaeger tracing的實現,通過自研設計和實現了Metric采集、聚合和關聯等邏輯。
- 分層和插件化
整體SDK架構分層清晰,基于Opentracing標準接口,相關底層和框架層都可以擴展實現一些個性功能,通過插件化設計來按需加載使用。
- 全量和采樣
Metric指標全量采集并聚合后上報。Trace Span明細需要采樣,支持遠程控制的動態前置采樣,以及有損后置采樣方案。
4.服務端架構介紹
圖片
采集、上報和控制
- Server App:Trace SDK在應用服務框架層進行自動化采集和上報
- Client App:集成在信令SDK層進行自動化采集和上報
- Sdk Control:sdk遠程控制服務,包括采樣策略、日志打印、功能啟停等控制
- Collector:數據接收服務,處理流控、驗證、清洗、轉換等邏輯
存儲、分析和告警
- Trace Sinker:spans明細數據的解析和存儲,按自研模型設置具體明細tags和logs
- Metric Sinker:指標數據解析和存儲,按自研模型設置相應的指標維度tags
- Meta Data Analyzer:分析出鏈路元數據,包含:請求uri、接口名、服務名、進程實例等
- Error Analyzer:分析時間線錯誤和異常來發現問題,再通過指標關聯和鏈路追蹤來定位根因
可視化和告警輸出
- Web Server:產品后端的API服務,負責數據檢索和業務邏輯處理
- Web/H5 App:產品前端的頁面展示、交互處理等可視化能力
- Wechat/SMS:企業微信、短信等方式的告警輸出
5.錯誤分析 - 應用性能根因定位
圖片
上圖右邊可以看到對請求處理流程的進一步解析,核心在于如何把請求處理追蹤和線程資源進行關聯,我們設計了反映服務處理能力的指標:線程負載率
上圖左邊的算法示例可以看到能發現應用服務GiftServer出現了線程負載高,應用性能不足問題,通過各請求的負載率分布來進一步分析,可以發現是由于/sendGift請求處理導致,而它里面的RPC請求/payMoney是根因問題。
效果示例:
圖片
6.錯誤分析 - 全鏈路根因定位
圖片
- Metric錯誤檢測
如上圖綠色框內是對應用服務內部Handle和RPC模型各類指標進行錯誤檢測:
Request Metrics // 請求指標
uri: /payMoney // 請求uri或方法名
totalCount: 1000 // 總請求數
errorCount: 200 // 錯誤請求數
latency avg: 2000ms // 請求平均耗時
errorRate: 20% // 請求錯誤率
...
發現請求錯誤率和平均耗時增加并在幾個周期內連續出現,按對應的告警分析規則就會判定為異常并產生實時告警發送給用戶。
- Metric關聯分析
如上圖指標的tag會記錄相應維度信息來建立指標關聯,并通過的指標和鏈路關聯來進行錯誤根因分析:
service: GiftServer // 應用服務名
host: 192.168.1.1:8080 // 服務實例ip port
peerService: MoneyServer // rpc對端服務名
peerHost: 192.168.1.2:8081 // rpc對端實例ip port
type: rpc // 請求類型
service: MoneyServer // 應用服務名
host: 192.168.1.2:8081 // 服務實例ip port
peerService: Mysql // rpc對端服務名
peerHost: 192.168.1.3:3306 // rpc對端實例ip port
type: mysql // 請求類型
建立關聯:
請求: /sendGift 調用 /payMoney
服務: GiftServer 調用 MoneyServer
實例: 192.168.1.1:8080 調用192.168.1.2:8081
- Metric & Trace & Log
如上圖底部所示,通過從Metric宏觀錯誤告警到下鉆Trace/Log明細的關聯分析,建設實時全鏈路根因定位的平臺能力。
三、效果展示
1.全鏈路根因分析
圖片
如上圖全鏈路拓撲圖展示錯誤根因節點和被影響鏈路節點,點擊節點可以進一步按被調、主調和實例視圖來查看宏觀指標情況,其中我們定位到是/hikari/getConnection耗時比較長導致,我們還可以點擊鏈路按鈕來進一步下鉆分析。
2.鏈路 - Trace明細分析
點擊鏈路按鈕后打開Trace鏈路明細頁面,可以看到每次請求的明細鏈路情況,點擊其中一條出錯的Trace,就可以看到如上圖所示的請求調用鏈視圖。可以快速分析定位到根因是獲取鏈接/hikari/getConnection的耗時長,導致上游的/getUser請求處理超時。
3.指標 - 應用性能分析
圖片
點擊指標按鈕后可以看具體的應用進程性能,通過右圖表請求處理的線程負載占比可以看到請求 /getUser 調用 /hikari/getConnection的線程負載率占比較高,左圖表線程狀態分析發現其根因是由于大多數工作線程阻塞在獲取連接的操作上。
4.指標 - 請求性能分析
圖片
來進一步看更多的請求性能指標,通過右圖表請求調用關系時延可以看到請求 /getUser 調用 /hikari/getConnection的平均耗時很大,左圖表可以分析具體的請求耗時區間分布占比情況,通過以上各種時序折線圖幫助我們快速分析具體的指標異常和變化趨勢。
5.告警分析 - 單節點聚集性問題
圖片
如上圖一站式排障流程,錯誤詳情頁面由上至下展示了錯誤基礎信息、錯誤類型分布圖等,這里可重點介紹一下中間的多節點調用聚合性根因定位:
鏈路 /getUser(sim-client) // URI接口(應用服務名)
-> /getUser(sim-first)
-> /getUser(sim-second:10.66.109.165:8001) // URI接口(應用服務名:實例ip:端口)
根因 Read timed out... // trace span log存儲的異常信息,也可進一步看異常堆棧
主調影響范圍如下表:
主調服務:實例ip:端口 | 超時率(%) | 請求數 | 平均耗時(ms) |
sim-client:10.116.18.223:8000 | 37.94 | 833 | 1070 |
sim-client:10.116.18.223:8000 | 33.52 | 880 | 1014 |
sim-client:10.116.18.223:8000 | 32.18 | 895 | 997 |
總結:從上面信息可以直接看出多個節點主調發生超時異常,是由于鏈路的根因節點sim-second:10.66.109.165:8001導致,并能快速把范圍性影響的根因聚集到具體出錯節點上。該場景的核心就是把請求全鏈路 & 多節點聚集性進行關聯分析。
6.告警分析 - 應用性能瓶頸問題
如上圖一站式排障流程,錯誤詳情頁面由上至下展示了錯誤基礎信息、線程負載率時序圖等,還是重點介紹中間的請求負載根因定位:
線程池名 tomcat.threadpool // 關聯當前服務框架的工作線程池
線程池快照 最大容量(200) 執行中(200) 阻塞中(190) // 關聯線程池資源指標
線程負載分布如下表:
請求URI | 負載率(%) | 請求數 | 平均耗時(ms) |
/getUser | 98.82 | 606 | 17417 |
/getUser 調用 /hikari/getConnection | 93.24 | 610 | 16632 |
/getUser 調用 /hikari/xiwi/SELECT | 5 | 606 | 983 |
總結:從上面信息可以一直看出工作線程池已經跑滿,而且大部分線程執行中遇到了阻塞等待,從負載率具體請求分布來看,根因是由于/getUser 調用 /hikari/getConnection占比較高導致。該場景的核心就是把請求處理 & 線程 & 連接進行關聯分析。
四、開放賦能
圖片
自從APM可觀測平臺上線運營后,除了用戶對產品一些反饋需求,也收到了很多對于平臺能力開放的需求,因此我們建設了APM開放平臺,用于開放能力賦能公司其他團隊,如上圖所示:
Case1:Metric時序數據
賦能AIOps異常檢測,提供各應用服務的請求時序數據給AI模型訓練,對部分個性服務和指標提供AI告警。
Case2:Trace明細數據
賦能自動化測試請求追蹤,自動化測試可以快速從客戶端到服務端全鏈路獲取錯誤根因,集成在自身系統邏輯中。
Case3:Trace包裹傳遞
賦能全鏈路請求染色,如對某個用戶進行染色后,會保障用戶uid隨著trace上下文在整個請求鏈路進行透明傳遞,各應用服務都可通過trace sdk的api獲取用戶uid來打印日志或其他操作。
總結:APM可觀測平臺這塊在虎牙統一可觀測規劃上屬于應用監控/鏈路追蹤,我們也在推進基礎設施監控、業務監控一起做一些整合,關鍵切入點還是在于各監控平臺元數據的關聯分析,后續有機會再介紹這塊的思考和實踐。
Q&A
Q1:對應用有沒有性能影響?
A1:Metric數據對應用性能影響非常小,主要是在異步線程中做相關聚合運算,也就是說會把請求明細span按模型的指標定義來做聚合,生成請求量、耗時分布、錯誤量等指標,一個周期內10000次請求也只會對指標值做改變,如:請求量: 10000次。但Trace span明細數據量是和請求量相關的,也就是采樣率100%的情況下當前節點會上報10000個span,在測試中發現對應用進程會有不少性能開銷,如果都上報的話對網絡流量和存儲也會開銷比較大,而大多數的明細span在實踐中價值不大,所以會采用一些前置采樣加有損后置采樣的策略來降低對整體性能和成本的影響。
Q2:鏈路span是怎么跟那個時候的日志和指標關聯?
A2:SDK會根據Handle和RPC模型把Metric指標設置各種維度tag,這些tag會跟Trace span tag保持對應來關聯請求調用鏈指標和資源指標,而Trace span log會關聯保存一些詳細異常日志和框架層日志。例如PPT分享的錯誤分析之應用性能根因定位和全鏈路根因定位里有詳細介紹這塊的實現原理,進一步在PPT效果展示中也可以看到把Metric&Trace&Log進行關聯分析后的產品效果和應用場景。
Q3:開發人員自定義的日志可以采集嗎?
A3:Java主要使用基于slf4j的log4j或logback實現,我們對此在SDK開發了一個MDC(Mapped Diagnostic Context)擴展,在日志里自動帶上traceId、spanId等信息,而C++也把相應能力集成在框架日志組件中。這些自定義日志落盤后會被采集上報,在Log日志平臺中可查詢展示,我們也跟日志平臺在產品層做了打通聯動,會自動帶上trace id條件來查詢該請求鏈路上的所有自定義日志明細。
匡凌軒虎牙直播 基礎保障部 SRE平臺負責人
- 負責虎牙應用發布、元數據、計量計費、監控和告警等平臺建設,主導應用監控和鏈路追蹤項目的從零到一實踐落地;曾任職歡聚時代集團,負責YY直播Web研發團隊,主導業務高可用、高并發分布式服務架構設計和實現,保障過多屆年度盛典等海量用戶業務場景。