咱們以前單體應(yīng)用里面有很多的應(yīng)用和功能,依賴各個功能之間相互調(diào)用,使用公共的代碼包等等,排查問題,使用類似于 gdb/dlv 工具或者直接查看代碼日志,進行定位和分析
但是現(xiàn)在我們基本上都是微服務(wù)架構(gòu)了,將以前的單體架構(gòu)拆成了一個個獨立的微服務(wù),現(xiàn)在就變成了多個微服務(wù)之間的相互調(diào)用的關(guān)系
在一個業(yè)務(wù)鏈條中,中間可能涉及到幾個,十幾個甚至幾十個微服務(wù)的交互和配合,如果中間某一環(huán)出現(xiàn)了問題,那么我們是很難排查的,排查問題耗時耗力,且效率極其低下
服務(wù)數(shù)量多,鏈路復(fù)雜,排查困難,大佬們就想出了一個辦法,使用分布式鏈路追蹤來處理這個問題
本文分別從以下幾個方面來聊聊關(guān)于分布式鏈路追蹤的技術(shù)知識:
- 什么是分布式鏈路追蹤
- 分布式鏈路追蹤的基礎(chǔ)原理
- 目前常用的分布式鏈路追蹤組件
- Jaeger 的基本架構(gòu)和使用演示
?什么是分布式鏈路追蹤
分布式鏈路追蹤,見名知意,這是用在分布式系統(tǒng)中,用于追蹤服務(wù)調(diào)用鏈路的
文章開頭有說到,微服務(wù)架構(gòu)中,存在大量的微服務(wù),且維護的團隊不盡相同,使用的語言也不太一致
線上部署幾百上千臺服務(wù)器,若鏈路出現(xiàn)了問題,性能出現(xiàn)了瓶頸,我們?nèi)绾闻挪椋?如何有效的解決呢?
分布式鏈路追蹤他就可以將一次分布式請求還原成調(diào)用鏈路,將一次分布式請求的調(diào)用狀況集中展示,且他還提供友好的 UI 界面,咱們直接在頁面上就能直觀的看到每一個服務(wù)的耗時請求到具體哪臺服務(wù)器上以及服務(wù)相應(yīng)的狀態(tài)等等????。
在技術(shù)上通常使用
- Tracing 表示鏈路追蹤
主要是用于單個請求的處理流程,包括服務(wù)調(diào)用和服務(wù)處理時長等信息
目前分布式上使用的比較多的是 Jaeger
- Logging 日志記錄
主要是用來記錄離散的日志事件。可以理解為你程序打印出來的一些日志
對于日志記錄,我們一般會使用 ELK ,這是 elastic 公司提供的一套解決方案,其中每一個字母代表一個開源組件
E: Elasticsearch
L: Logstash
K:Kibana
- Metrics 數(shù)據(jù)聚合
用于聚合數(shù)據(jù)的,通常是有時間順序的數(shù)據(jù)
對于數(shù)據(jù)聚合和統(tǒng)計系統(tǒng),我們一般使用 Prometheus 普羅米修斯來進行處理
可以看到上述這三個概念是相輔相成的,僅僅只使用一種方式,是沒有辦法完全滿足我們需求的,在實際生產(chǎn)過程中,會將上述進行兩兩組合來達到我們期望的效果。
??Tracing 與 Logging 組合
既有鏈路追蹤又有日志
那么我們就可以達到的效果是在我們每一個請求階段,可以看到詳細的標(biāo)簽數(shù)據(jù)對應(yīng)的日志數(shù)據(jù)以及錯誤原因
??Tracing 與 Metrics 組合
既有鏈路追蹤,又有數(shù)據(jù)統(tǒng)計
那我們就可以去做單個請求中的可計量數(shù)據(jù),比如說,我們的接口調(diào)用次數(shù)以及調(diào)用時長等等
??Logging 與 Metrics 組合
既有日志數(shù)據(jù)又有數(shù)據(jù)統(tǒng)計
咱們就可以去做數(shù)據(jù)聚合事件,去統(tǒng)計某一段時間某一類接口的請求總數(shù),報錯次數(shù),成功率等等。
?分布式鏈路追蹤的基礎(chǔ)原理
那知道上述的一些應(yīng)用場景之后,是否會對分布式鏈路追蹤的技術(shù)原理有那么一點興趣了呢?那么我們開始吧。
無論分布式鏈路追蹤組件有多少,他們都有三個核心的步驟。
- 代碼 埋點
- 數(shù)據(jù)存儲
- 查詢展示
市面上那么多鏈路,追蹤主線那么自然,是要遵循一個統(tǒng)一的規(guī)范的這個規(guī)范,就是 OpenTracing
OpenTracing 可以理解為就是一個標(biāo)準(zhǔn)化的庫,它位于應(yīng)用程序和鏈路追蹤程序之間,它解決了分布式追蹤 API 不兼容的問題,我們可以理解為是這樣的。
[圖片上傳失敗...(image-312de8-1695819940905)]
無論哪一種鏈路追蹤組件一定會有如下這樣的做法
[圖片上傳失敗...(image-9e6f22-1695819940905)]
通過上圖就可以看到
- 需要在應(yīng)用程序中做埋點,數(shù)據(jù)上報到對應(yīng)的鏈路追蹤組件的收集器上,并對數(shù)據(jù)存儲
- 另外一條路便是前端 UI 來查詢數(shù)據(jù)進行展示
?鏈路追蹤如何實現(xiàn)?
架構(gòu)基本上也知道了,那么它具體的實現(xiàn)細節(jié)是什么樣的呢?
鏈路追蹤中一條鏈路也就可以理解為是一個 Trace 樹,一個樹上面有多個 Span 基本單元
Span 基本單元有自己的唯一標(biāo)識,通常是 UUID,還有其他的一些信息,例如時間戳,鍵值對,ParentID 以及當(dāng)前的 SpanID 等等信息。
[圖片上傳失敗...(image-6afafb-1695819940905)]
可以看到整個鏈路,其實就是一個有向無環(huán)圖。
- 我們可以看到一條調(diào)用鏈的第1 個 Span ,它的 ParentID是空的,這一個 Span 就被稱為RootSpan
- 那其他的 Span 自身的 ParentID 就是上一個 SpanID,自己的 SpanID 就是下一個 Span 的 ParentID
?目前常用的分布式鏈路追蹤組件
目前常用的分布式鏈路追蹤組件有這些
- Twitter Zpikin
- Jaeger
- SkyWalking
- Pinpoint
其中 Twitter Zpikin 的架構(gòu)和實現(xiàn)相對簡單,Jaeger 也是借鑒了google 的 Dapper 論文和 OpenZipkin 的啟發(fā)
接下來的兩個并沒有提供 golang 版本的庫,因此就不過多贅述了,接下來主要著重介紹的是
- Jaeger
?Jaeger 的基本架構(gòu)
Jaeger Uber 開源的分布式鏈路追蹤系統(tǒng),它用于微服務(wù)的監(jiān)控和排查,并且支持分布式上下文傳播和分布式事務(wù)的監(jiān)控,報錯分析,服務(wù)的調(diào)用網(wǎng)絡(luò)分析,和性能/延遲優(yōu)化
它的服務(wù)端的代碼就是 GO 語言實現(xiàn)的,自然也提供了 GO 語言版本的客戶端代碼庫
github.com/uber/jaeger-client-go
Jaeger 的基本架構(gòu)圖是這樣的
[圖片上傳失敗...(image-f88122-1695819940905)]
可以看到 Jaeger 的架構(gòu)圖與上述 OpenTracing 的規(guī)范大同小異,只不過自身服務(wù)端處理的有一些變動,整體方向上按照規(guī)范來的
Jaeger 是支持多個存儲后端,且原生支持 OpenTracing 規(guī)范,擁有可視化友好的UI界面,支持云原生部署,且還能兼容 Zipkin 格式的請求
官方文檔上也可以看到關(guān)于支持的存儲后端有這些:
[圖片上傳失敗...(image-195a77-1695819940905)]
?Jaeger 使用
- 現(xiàn)在自己的虛擬機上面裝一個 Jaeger 的服務(wù)端,官方有提供一鍵 docker 運行的版本,叫做 All-in-One ,這個僅僅是用來實驗,如果是要放在正式環(huán)境,請參考官方文檔進行環(huán)境部署
https://www.jaegertracing.io/docs/1.12/deployment/
$ docker run -d --name jaeger \
-e COLLECTOR_ZIPKIN_HTTP_PORT=9411 \
-p 5775:5775/udp \
-p 6831:6831/udp \
-p 6832:6832/udp \
-p 5778:5778 \
-p 16686:16686 \
-p 14268:14268 \
-p 9411:9411 \
jaegertracing/all-in-one:1.12
安裝完畢之后,我們直接訪問 Jaeger 的前端即可,前端暴露的端口是 16686 , http://localhost:16686
[圖片上傳失敗...(image-c831b4-1695819940905)]
??Jaeger demo
咱們簡單寫一個 Jaeger 的例子,僅僅是在一個應(yīng)用中,模擬 test1 -> testtest1-1 的一個鏈路
package main
import (
"log"
"time"
jaegerCfg "github.com/uber/jaeger-client-go/config"
"github.com/opentracing/opentracing-go"
"github.com/uber/jaeger-client-go"
"context"
)
func main() {
// 初始 log 日志
log.SetFlags(log.LstdFlags | log.Lshortfile)
// 配置 Jaeger
cfg := jaegerCfg.Configuration{
Sampler: &jaegerCfg.SamplerConfig{
Type: jaeger.SamplerTypeConst,
Param: 1,
},
Reporter: &jaegerCfg.ReporterConfig{
LogSpans: true,
LocalAgentHostPort: "127.0.0.1:6831",
},
}
// 創(chuàng)建一個全局的 Jaeger tracer
closer, err := cfg.InitGlobalTracer(
"testSvr",
)
if err != nil {
log.Printf("InitGlobalTracer error: %s", err.Error())
return
}
var ctx = context.TODO()
span1, ctx := opentracing.StartSpanFromContext(ctx, "test1")
// 模擬業(yè)務(wù)處理
time.Sleep(time.Second)
span11, _ := opentracing.StartSpanFromContext(ctx, "test1-1")
// 模擬業(yè)務(wù)處理
time.Sleep(time.Second)
span11.Finish()
span1.Finish()
defer closer.Close()
}
通過程序代碼,我們可以知道
- 是給 Jaeger 的 6831 這個端口發(fā)送 ******Udp** 包
- Jaeger 是 opentracing.StartSpanFromContext ,在上下文上傳入我們當(dāng)前的 operationName 來進行處理的,效果可以見后續(xù)的圖
運行代碼的時候,如果你的環(huán)境里面不是 golang 1.18 的話,則會出現(xiàn)這樣的報錯,此時需要先卸載當(dāng)前環(huán)境中的 golang,再去安裝新版本的 golang
[圖片上傳失敗...(image-24d99b-1695819940905)]
如果不是先卸載,再安裝,那么會出現(xiàn)一些庫報錯的問題,例如這樣
[圖片上傳失敗...(image-ca5b7a-1695819940905)]
環(huán)境 ok 之后,我們直接訪問環(huán)境地址+上16686端口就可以看到如下頁面
- 選擇 Service 為 testSvr
- 查看具體的 Trace
[圖片上傳失敗...(image-4bba1f-1695819940905)]
[圖片上傳失敗...(image-212635-1695819940905)]
此處可以看到調(diào)用關(guān)系為 test1 調(diào)用了 test1-1,其中 test1 自身處理事項耗時 1s,等待 test1-1 處理事項 1s,因此整個鏈路耗時 2s
對于鏈路追蹤,咱們需要知道的是原理,知道原理之后,編碼都是很簡單的事情,上述僅是一個簡單的 demo,主要是展示如何去使用這個鏈路追蹤組件
實際業(yè)務(wù)中,我們會對微服務(wù)之間的交互進行鏈路追蹤,并且會從前端請求進來就會開始記錄
這個時候,我們涉及到 http 中的代碼 埋點,grpc 中的代碼埋點,自然 Jaeger 都是有相應(yīng)的中間件和攔截器來進行使用的,實際上都是對 ctx 上下文上面做文章,這里就不過多贅述了,將 Jaeger 的代碼下載到本地,稍微閱讀一下就可以知道了
使用鏈路追蹤,我們就可以很清晰的看到一條完整的調(diào)用鏈,每一個環(huán)節(jié)耗時多少,整體來看性能的瓶頸在哪里就可以做到一清二楚,先用起來了吧,看看源碼
會使用到這些庫
"github.com/grpc-ecosystem/go-grpc-middleware/tracing/opentracing"
"github.com/uber/jaeger-client-go/config"
"github.com/opentracing/opentracing-go"
"github.com/uber/jaeger-client-go"
感謝閱讀,歡迎交流,點個贊,關(guān)注一波 再走吧
歡迎點贊,關(guān)注,收藏
朋友們,你的支持和鼓勵,是我堅持分享,提高質(zhì)量的動力
[圖片上傳失敗...(image-b2de93-1695819940905)]
好了,本次就到這里
技術(shù)是開放的,我們的心態(tài),更應(yīng)是開放的。擁抱變化,向陽而生,努力向前行。
我是阿兵云原生,歡迎點贊關(guān)注收藏,下次見~
文中提到的技術(shù)點,感興趣的可以查看這些文章: