Go微服務(wù)架構(gòu)實(shí)戰(zhàn)-【公粽號(hào):堆棧future】
原文
Go微服務(wù)架構(gòu)實(shí)戰(zhàn)目錄
1. 微服務(wù)架構(gòu)上篇
1. grpc技術(shù)介紹
2. grpc+protobuf+網(wǎng)關(guān)實(shí)戰(zhàn)
3. etcd技術(shù)介紹
4. 基于etcd的服務(wù)發(fā)現(xiàn)與注冊(cè)
5. 基于etcd的分布式鎖實(shí)戰(zhàn)
2. 微服務(wù)架構(gòu)中篇
5. 基于ingress和service實(shí)現(xiàn)灰度發(fā)布
3. 微服務(wù)架構(gòu)下篇
分布式鏈路追蹤實(shí)戰(zhàn)
干貨:
什么是APM
什么是Opentracing
什么是SpanID
什么是TraceID
基于zipkin構(gòu)建鏈路追蹤
1. 什么是APM
APM(Application Performance Management,即應(yīng)用性能管理,在分布式領(lǐng)域也稱為分布式跟蹤管理)對(duì)企業(yè)的應(yīng)用系統(tǒng)進(jìn)行實(shí)時(shí)監(jiān)控,它是用于實(shí)現(xiàn)對(duì)應(yīng)用程序性能管理和故障管理的系統(tǒng)化的解決方案。
APM核心功能:
- 服務(wù)調(diào)用跟蹤
- 應(yīng)用系統(tǒng)存活檢測(cè)
- 監(jiān)控告警
開源APM管理工具:
- ZipKin
- PinPoint
- SkyWalking
- Prometheus
我們這篇文章主要是講解APM的核心功能之一:服務(wù)調(diào)用跟蹤,用到的工具是ZipKin,本來想用Prometheus搭建一個(gè)監(jiān)控平臺(tái),想來想去比較簡單,大家直接在本地就可以搭建單機(jī)版的監(jiān)控平臺(tái)。
2. 什么是Opentracing
OpenTracing通過提供平臺(tái)無關(guān)、廠商無關(guān)的API,使得開發(fā)人員能夠方便的添加(或更換)追蹤系統(tǒng)的實(shí)現(xiàn)。
不過OpenTracing并不是標(biāo)準(zhǔn)。因?yàn)镃NCF不是官方標(biāo)準(zhǔn)機(jī)構(gòu),但是它的目標(biāo)是致力為分布式追蹤創(chuàng)建更標(biāo)準(zhǔn)的API和工具。
3. 什么是TraceID
一個(gè)trace代表了一個(gè)事務(wù)或者流程在(分布式)系統(tǒng)中的執(zhí)行過程,而這個(gè)過程會(huì)有唯一ID去標(biāo)識(shí),這個(gè)唯一ID就是Trace ID,通俗解釋就是一個(gè)API請(qǐng)求的完整調(diào)用流程。
4. 什么是SpanID
一個(gè)span代表在分布式系統(tǒng)中完成的單個(gè)工作單元,這個(gè)工作單元有唯一ID去標(biāo)識(shí),這個(gè)唯一ID就是Span ID。也包含其他span的“引用”,這允許將多個(gè)spans組合成一個(gè)完整的Trace。
通俗解釋就是在Trace這樣一個(gè)完整調(diào)用的流程中,Span扮演的角色就是每次執(zhí)行的一次IO或者非IO操作。所以你通過Trace找到整個(gè)鏈路,然后從鏈路中找到確定的Span,這樣就可以準(zhǔn)確定位一次問題或者性能查詢。
5. 其他名稱解釋
Span tags(跨度標(biāo)簽)可以理解為用戶自定義的Span注釋。便于查詢、過濾和理解跟蹤數(shù)據(jù)。
Span logs(跨度日志)可以記錄Span內(nèi)特定時(shí)間或事件的日志信息。主要用于捕獲特定Span的日志信息以及應(yīng)用程序本身的其他調(diào)試或信息輸出。
SpanContext 代表跨越進(jìn)程邊界,傳遞到子級(jí)Span的狀態(tài)。常在追蹤示意圖中創(chuàng)建上下文時(shí)使用。
6. 案例
圖中可以看到以下內(nèi)容:
- 執(zhí)行時(shí)間的上下文
- 服務(wù)間的層次關(guān)系
- 服務(wù)間串行或并行調(diào)用鏈
結(jié)合以上信息,在實(shí)際場景中我們可以通過整個(gè)系統(tǒng)的調(diào)用鏈的上下文、性能等指標(biāo)信息,一下子就能夠發(fā)現(xiàn)系統(tǒng)的痛點(diǎn)在哪兒。
7. 什么是ZipKin
Zipkin是分布式追蹤系統(tǒng)。它的作用是收集解決微服務(wù)架構(gòu)中的延遲問題所需的時(shí)序數(shù)據(jù)。它管理這些數(shù)據(jù)的收集和查找。
Zipkin的設(shè)計(jì)基于Google Dapper論文。
8. 基于ZipKin構(gòu)建鏈路追蹤
首先在基于之前的項(xiàng)目之中,把server.go修改一下,讓其支持分布式鏈路追蹤。server.go:
<pre data-tool="mdnice編輯器" style="box-sizing: border-box !important; margin: 10px 0px; padding: 0px; outline: 0px; font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 14px; overflow: auto; display: block; color: rgb(33, 37, 41); max-width: 100%; overflow-wrap: break-word !important; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: 0.8px; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0.8px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">`const (
SERVICE_NAME = "simple_zipkin_server"
ZIPKIN_HTTP_ENDPOINT = "http://127.0.0.1:9411/api/v2/spans" //上報(bào)到ZipKin中的鏈路
ZIPKIN_RECORDER_HOST_PORT = "0.0.0.0"
)
func main() {
...
//鏈路日志輸出到哪
reporter := httpreporter.NewReporter(ZIPKIN_HTTP_ENDPOINT)
defer reporter.Close()
//記錄服務(wù)名稱和端口
endpoint, err := zipkin.NewEndpoint(SERVICE_NAME, ZIPKIN_RECORDER_HOST_PORT)
if err != nil {
log.Fatalf("zipkin.NewEndpoint err: %v", err)
}
tracer, err := zipkin.NewTracer(reporter, zipkin.WithLocalEndpoint(endpoint))
if err != nil {
log.Fatalf("zipkin.NewTracer err: %v", err)
}
//接入opentracing
t := zipkinot.Wrap(tracer)
opentracing.SetGlobalTracer(t)
logrus.Infof("starting hello service at: %s", *port)
//初始化grpc server,并注冊(cè)中間件
s := grpc.NewServer(
// otgrpc.LogPayloads 是否記錄 入?yún)⒑统鰠?br>
// otgrpc.SpanDecorator 裝飾器,回調(diào)函數(shù)
// otgrpc.IncludingSpans 是否記錄
grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(otgrpc.OpenTracingServerInterceptor(t,
otgrpc.LogPayloads(),
// IncludingSpans是請(qǐng)求前回調(diào)
otgrpc.IncludingSpans(func(parentSpanCtx opentracing.SpanContext, method string, req, resp interface{}) bool {
log.Printf("method: %s", method)
log.Printf("req: %+v", req)
log.Printf("resp: %+v", resp)
return true
}),
// SpanDecorator是請(qǐng)求后回調(diào)
otgrpc.SpanDecorator(func(span opentracing.Span, method string, req, resp interface{}, grpcError error) {
log.Printf("method: %s", method)
log.Printf("req: %+v", req)
log.Printf("resp: %+v", resp)
log.Printf("grpcError: %+v", grpcError)
}),
))),
)
//注冊(cè)服務(wù)
pb.RegisterGreeterServer(s, &server{})
fmt.Println("ddd")
s.Serve(lis)
}` </pre>
至此我們的grpc服務(wù)就有了鏈路追蹤功能,接下來我們演示下,啟動(dòng)server.go:k8s-grpc-demo go run cmd/svr/svr.go -port 50004
然后啟動(dòng)客戶端:k8s-grpc-demo go run cmd/cli/cli.go
當(dāng)我們點(diǎn)擊某一個(gè)Trace的時(shí)候,就進(jìn)入這個(gè)Trace的整個(gè)調(diào)用鏈路詳情中:
這樣我就基于gRPC + Opentracing + Zipkin的分布式鏈路追蹤系統(tǒng)就搭建完成了,大家下去可以自己嘗試下。
9. 小結(jié)
各位讀者朋友們,我們的Go微服務(wù)架構(gòu)實(shí)戰(zhàn)【上中下】系列課程到這里就基本上結(jié)束了,寫作過程中雖然很累,很艱辛,但是這個(gè)系列能在有限的業(yè)余時(shí)間堅(jiān)持創(chuàng)作完實(shí)屬不易,希望在之后的業(yè)余時(shí)間當(dāng)中能繼續(xù)為大家?guī)砀舻南盗姓n程,歡迎大家點(diǎn)贊、關(guān)注和分享。
最后再次感謝大家對(duì)本系列課程的大力支持,由于個(gè)人能力有限,難免哪里寫的有問題歡迎大家指出,也歡迎各位能在百忙之中抽出時(shí)間學(xué)習(xí),最后和各位分享一句話:簡單的東西不一定是最好的,但最好的東西一定是簡單的。