技术分享 | jaeger链路日志实现
源寶導讀:隨著企業應用越來越復雜,內部的調用鏈條越來越長,性能問題也變得越來越難以定位和排查,為了應對此問題,我們在移動平臺中引入了“jaeger調用鏈追蹤工具”,幫助我們高效定位云端服務的性能問題。本文將分享我們相關的技術實踐。
一、背景
? ? 大家好,很幸運代表團隊和大家分享一下,天際-移動平臺團隊在實現分布式鏈路日志追蹤過程的心路歷程。移動應用的后臺服務,其內部調用鏈路往往很復雜,一旦發現性能問題,很難快速精準的定位,嚴重影響研發小伙伴們的幸福感。具體問題表現在這幾個方面:
容器內日志簡單,某些前后端數據不一致導致的的問題無法定位。
PaaS小程序微服務化,服務之間調用雖然有嚴格規定,但是出現問題時還是無法快速定位問題的出處。
測試人員登記bug需要粘貼詳細的請求、響應,開發通過創造數據,模擬這個請求來慢慢排查問題所在。
二、技術選型
移動平臺中關于PaaS小程序后端的現有架構:
? ? 從上圖中可知,我們當前同時支持了PHP、Go、Nodejs三種編程語言構建的應用,如果要做日志的鏈路追蹤,起碼需要兼容多編程語言。
? ? 通過分析,我們總結出“日志追蹤工具”應滿足的條件:
支持多語言。保證PHP、Go、Nodejs都可以接入日志,才能形成完整鏈路。
一定是無侵入式的。這樣在多個服務中埋點比較方便,日志服務升級維護成本也不會高。
對于特定標簽的日志可以通過微信、郵箱甚至短信的方式通知到開發或者運維同學。
能夠對API接口的性能統計分析。
由于我們使用的阿里云日志,日志服務最好可以將阿里云日志作為數據存儲。
三、jaeger工具介紹
3.1、簡介
? ? Jaeger是由Uber開源的分布式追蹤系統,一套完整的Jager追蹤系統包括Jaeger-client、Jaeger-agent、Jaeger-collector、Database和Jaeger-query UI等基本組件。
3.2、Jaeger的優勢
采用Open Tracing標準,支持跨語言。
分布式上下文傳播。
分布式是鏈路追蹤。
服務依賴性分析。
性能延遲監控。
3.3、jaeger的技術原理
架構圖:
jaeger-client:jaeger 的客戶端,實現了opentracing協議。
jaeger-agent:jaeger-client 的一個代理程序,client將收集到的調用鏈數據發給agent,然后由agent發給collector。
jaeger-collector:負責接收jaeger client或者jaeger agent上報上來的調用鏈數據,然后做一些校驗,比如時間范圍是否合法等,最終會經過內部的處理存儲到后端存儲。后端存儲是一個可插拔的組件,Jaeger on Aliyun Log Service 增加了對阿里云日志服務的支持。
jaeger-query:專門負責調用鏈查詢的一個服務,有自己獨立的UI。
spark-job:基于spark的運算任務,可以計算服務的依賴關系,調用次數等。
? ? 說明:其中jaeger-collector和jaeger-query是必須的,其余的都是可選的,我們采用agent上報的方式,讓客戶端上報日志到agent,以減少部分性能消耗。jaeger-collector支持Aliyun Log Service,也是很好的滿足我們要求。
? ? aliyun-log-jaeger-collector配置表:
3.4、日志
單條鏈路:
? ? 可以清晰的看到一個請求的發起時間,所經過的服務數量、所調用服務的依賴關系、消耗的時長等信息。
3.5、技術名詞解釋
service:微服務的名稱或者標識。
operation:一個span的名稱,簡單易讀。
span:系統中具有開始時間和執行時長的邏輯運行單元 。具體可以理解為一次方法調用, 一個程序塊的調用或者一次RPC/數據庫訪問。
tags:“鍵值對”形式的tags,一個span可以有多tags,tags是對span的簡單注解,不會被子級span繼承。tags value 的標準含義看參考https://opentracing.io/ specification/conventions
logs:一個span可以有多logs,每一個logs都可以自定名稱以及任意大小的存儲結構。
spanContext:跨進程邊界,傳遞到下級span的狀態,每個span都有訪問spanContext的方法。當在創建span時,向傳輸協議Inject(注入)從上級span傳輸協議中Extract(提取)的spanContext既可。
Inject and Extract:spanContext可以通過Injected操作向Carrier增加,或者通過Extracted從Carrier中獲取,跨進程通訊數據。通過這種方式,SpanContexts可以跨越進程邊界,并提供足夠的信息來建立跨進程的span間關系(因此可以實現跨進程連續追蹤)。
四、落地應用
4.1、??核心設計思路:
采用jaeger-client上報數據到jaeger-agent,再由jaeger-agent集中處理傳輸到jaeger-collector,之后jaeger-collector會將合法的數據存儲到阿里日志。
之后在我們需要時,可以通過jaeger-query + jaeger-ui來查詢日志。
我們采用jaeger的默認方式,將spanContext中跨進程數據(當前只有uber-trace-id)注入到header中,當下游服務在請求header中提取到對應的跨進程數據就會形成一個依賴和鏈路關系,如果沒有就生成一個新的供下游服務發現和關聯。
4.2、traceId傳遞方式
// 上游服務將traceId注入到header中$header = TraceJaeger::inject($header); // 下游服務解析獲取traceId,完成一個請求的傳遞 $target = []; foreach (request()->headers->all() as $key => $value) {$target[$key] = Arr::first($value); } $spanContext = $this->tracer->extract(TEXT_MAP, $target);4.3、應用結果
串行
traceId:1660cc5871c2df9e1660cc5871c34a59
并行
traceId:1660d1de34f6c7691660d1de34f5a93b
? ? 以上都是我們實際的調用場景,應用創建的改造前(串行),改造后(并行)。可以很清晰的看到服務之間的調用和所花費的時間。
? ? 我們打開可以看到app-service這個服務被調用的詳細信息。包括請求方式、請求數據、響應數據等。
4.4、兼容Go語言
1、go服務gin中間件使用開源框架,代碼倉庫:https://github.com/yuchanns/bullets
go get -u github.com/yuchanns/bullets2、中間件使用:
package main import ("context""github.com/gin-gonic/gin""github.com/yuchanns/bullets/common""github.com/yuchanns/bullets/common/middlewares""os" ) func main() {g := gin.Default()//服務名serviceName := "openapi-service"//上報agent地址agentAddr := os.Getenv("OPENTRACING_AGENT")//操作前綴operationPrefix := []byte("api-request-")opentracerCloseFunc, opentracerMiddleware, err := middlewares.BuildOpenTracerInterceptor(serviceName, agentAddr, operationPrefix)if err != nil {common.Logger.Error(context.Background(), err)} else {defer opentracerCloseFunc()g.Use(opentracerMiddleware)} }3、自定義打tag:
import ("github.com/gin-gonic/gin""github.com/opentracing/opentracing-go""github.com/opentracing/opentracing-go/log""github.com/pkg/errors" ) func CustomTag(ctx *gin.Context) {if cspan, ok := ctx.Get("tracing-context"); ok {if span, ok := cspan.(opentracing.Span); ok {span.SetTag("error", true)span.LogFields(log.Error(errors.New("err")))span.LogFields(log.String("exampleKey", "stringValue"))}} }4.5、兼容PHP語言
1、安裝composer包
composer require tracelog/jaeger2、根目錄執行
php artisan vendor:publish3、選擇發布配置?件
Tracelog\jaeger\config\jaeger.php文件拷貝到工程項目的config?錄4、修改配置?件
return['enabled' => env('JAEGER_ENABLED', true), //是否開啟'service_name' => env('JAEGER_SERVICE_NAME', env('APP_NAME', 'Laravel')), //服務名稱'agent' => [ 'host' => env('OPENTRACING_AGENT','0.0.0.0:6831'), //日志服務代理 地址],'watchers' => [Tracelog\jaeger\watchers\RequestWatcher::class, //請求日志監聽Tracelog\jaeger\watchers\FrameworkWatcher::class //項目日志推送] ]使? jukylin/jaeger-php 直接記錄。
參考:https://github.com/jukylin/jaeger-php/blob/master/example/HTTP.php
4.6、集成到Laravel Log
? ? 使?框架中Log??時,也可以將日志記錄到代理。針對當前框架情況修改(添加)/app/Common/StreamHandler ---> Handle
if (config('jaeger.enabled')){$span = TraceJaeger::client()->startSpan($record['message'],['child_of' => TraceJaeger::getRootSpan()]);$span->setTag('log.level', $record['level_name']);$span->log($record['context']);$span->finish();TraceJaeger::client()->flush(); }說明:對Nodejs的兼容,我們目前正在實現中。
五、總結
? ? 自從鏈路日志工具上線后,我們排查問題的效率有了很大提升。我們可以直接通過日志定位出有問題的后端服務,通過請求和響應數據快速判斷問題原因,極大的提高了工作效率和排查問題的幸福感!
------ END ------
作者簡介
智同學:?研發工程師,目前負責天際-移動平臺的研發工作。
也許您還想看
記AWSS3在iOS端的一次改造事件
明源云創CI/CD技術演進
微前端架構在容器平臺的應用
AI云店小程序演變之路
天眼探針基于rrweb實現前端異常視頻錄制與回放功能
總結
以上是生活随笔為你收集整理的技术分享 | jaeger链路日志实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 全网最通透的“闭包”认知 · 跨越语言
- 下一篇: [C#.NET 拾遗补漏]16:几个常见