日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

Go2sky -- Golang用skywalking实现全链路追踪

發(fā)布時(shí)間:2023/12/16 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Go2sky -- Golang用skywalking实现全链路追踪 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、背景介紹

? ? ? ? 由于在微服務(wù)架構(gòu)中,服務(wù)之間的調(diào)用關(guān)系多而復(fù)雜,所以有必要對(duì)它們之間的調(diào)用鏈路進(jìn)行追蹤、分析,判斷是哪里出了問(wèn)題,或者哪里耗時(shí)過(guò)多。

? ? ? ? 最近接到了這個(gè)需求,添加全鏈路追蹤,所以研究并實(shí)踐了一下,還不太深刻,若有錯(cuò)誤的地方歡迎指正。

二、OpenTracing相關(guān)概念介紹

? ? ? ? 首先,要實(shí)現(xiàn)全鏈路追蹤,必須先理解OpenTracing的一些基本概念。OpenTracing為分布式鏈路追蹤制定了一個(gè)統(tǒng)一的標(biāo)準(zhǔn)。只要是按照此標(biāo)準(zhǔn)實(shí)現(xiàn)的服務(wù),就能夠完整的進(jìn)行分布式追蹤。

? ? 1. Span

? ? ? ? Span可以被翻譯為跨度,可以理解為一次方法調(diào)用,一個(gè)程序塊的調(diào)用,或者一次RPC/數(shù)據(jù)庫(kù)訪問(wèn)。

? ??? ? Span之間是有關(guān)系的,child of 和 follow of。比如一次RPC的調(diào)用,RPC客戶端和服務(wù)端的span就形成了父子關(guān)系。

? ? 2. Trace

? ? ? ? Trace表示一個(gè)調(diào)用鏈,比如在分布式服務(wù)中,一個(gè)客戶端的請(qǐng)求,在后臺(tái)可能經(jīng)過(guò)了層層的調(diào)用,那么每一次調(diào)用就相當(dāng)于一個(gè)span,而這一整條調(diào)用鏈路,可以理解成一個(gè)trace。

? ??? ? Trace有一個(gè)全局唯一的ID。

三、Go2sky簡(jiǎn)介

? ??? ? Go2sky是Golang提供給開(kāi)發(fā)者實(shí)現(xiàn)SkyWalking agent探針的包,可以通過(guò)它來(lái)實(shí)現(xiàn)向SkyWalking Collector上報(bào)數(shù)據(jù)。

? ??? ? 快速入門:GitHub-Go2Sky

? ??? ??1. 創(chuàng)建Reporter、Tracer

? ??? ??? ? SkyWalking支持http和gRpc兩種方式收集數(shù)據(jù),在Go2sky中,想要上報(bào)數(shù)據(jù),先創(chuàng)建一個(gè)GRPCReporter.

? ? ? ??? ? Tracer代表了本程序中的一條調(diào)用鏈路。

? ? ? ? ? ??

? ? ? ? ? ? 本程序中的所有span都會(huì)與服務(wù)名為example的服務(wù)相關(guān)聯(lián)。

?

? ? ? ? 2. 創(chuàng)建Span

? ? ? ? ? ? Span有三種類型:LocalSpan、EntrySpan、ExitSpan。

? ? ? ? ? ? LocalSpan:可以用來(lái)表示本程序內(nèi)的一次調(diào)用。

? ? ? ? ? ? EntrySpan:用來(lái)從下游服務(wù)提取context信息。

? ? ? ? ? ? ExitSpan:? 用來(lái)向上游服務(wù)注入context信息。

? ? ? ? ? ??

? ? ? ? ? ? 在創(chuàng)建span時(shí),上下文參數(shù)傳入context.Backround() ,就表示它是root span。

?

? ? ? ? 3. 創(chuàng)建sub span

? ? ? ? ? ? 在創(chuàng)建LocalSpan和EntrySpan的時(shí)候,返回值會(huì)返回一個(gè)context信息(ctx),通過(guò)它來(lái)創(chuàng)建sub span,來(lái)與root span形成父子關(guān)系。

? ? ? ? ? ??

? ? ? ? 4. End Span

? ? ? ? ? ? 必須要確保結(jié)束span,它們才可以被上傳給skywalking。

? ? ? ? ? ??

?

? ? ? ? 5. 關(guān)聯(lián)Span

? ? ? ? ? ? 我們?cè)诔绦蛑袆?chuàng)建的span,是怎么關(guān)聯(lián)起來(lái)形成一個(gè)調(diào)用鏈的呢。

? ? ? ? ? ? 在同一個(gè)程序中,向上面那樣,創(chuàng)建root span 和 sub span即可。

? ? ? ? ? ? 在不同的程序中,下游服務(wù)使用ExitSpan向上游注入context信息,上游服務(wù)使用EntrySpan從下游提取context信息。Entry和Exit使得skywalking可以分析,從而生成拓?fù)鋱D和度量指標(biāo)。

? ? ? ? ? ??

?

四、實(shí)戰(zhàn) -- 跨程序追蹤RPC調(diào)用

? ? ? ? 看到這里,有了基本的概念,以及Go2sky的基本用法,但是仍然不能夠?qū)PC進(jìn)行有效的追蹤。

? ? ? ? 因?yàn)樯蠄D中的例子使用的是http請(qǐng)求,它本身就封裝了Get和Set方法,可以很輕松的注入和提取context信息。但是RPC請(qǐng)求并沒(méi)有,想要追蹤別的類型跨程序的調(diào)用也沒(méi)有。

? ? ? ? 所以我們要自己將context信息在進(jìn)行調(diào)用的時(shí)候,從下游服務(wù)傳給上游服務(wù),然后自己定義注入和提取的方法。

? ? ? ? 下面只貼出了鏈路追蹤部分的代碼,其它的比如rpc相關(guān)的部分代碼省略了(不然又臭又長(zhǎng),還難看)。

? ? 1. Client端 (下游服務(wù))

? ? ? ? 定義請(qǐng)求信息的結(jié)構(gòu)體:

type Req struct {A intHeader string // 添加此字段,用于傳遞context信息 }

? ? ? ? 定義context信息的注入方法:

func (p *Req) Set(key, value string) error {p.Header = fmt.Sprintf("%s:%s", key, value)return nil }

? ? ? ? 創(chuàng)建reporter和tracer:

r, err = reporter.NewGRPCReporter("192.168.204.130:11800") if err != nil {logs.Info("[New GRPC Reporter Error]: [%v]", err)return }// 這個(gè)程序中所有的span都會(huì)跟服務(wù)名叫RTS_Test的服務(wù)關(guān)聯(lián)起來(lái) tracer, err = go2sky.NewTracer("RTS_Test", go2sky.WithReporter(r), go2sky.WithInstance("RTS_Test_1")) if err != nil {logs.Info("[New Tracer Error]: [%v]", err)return } tracer.WaitUntilRegister()

? ? ? ? rpc調(diào)用以及創(chuàng)建span:

? ? ? ? 在創(chuàng)建ExitSpan的時(shí)候,傳入了一個(gè)函數(shù),函數(shù)實(shí)現(xiàn)就是我們定義的如何注入context信息的函數(shù)。

? ? ? ? 它會(huì)在CreateExitSpan()函數(shù)的內(nèi)部被調(diào)用,header的值不需要我們管,它在CreateExitSpan函數(shù)內(nèi)部生成的。我們只需要負(fù)責(zé)在上游服務(wù)中把它提取出來(lái)即可。

? ? ? ? 我目前的理解是,只需要在下游服務(wù)中負(fù)責(zé)把這個(gè)header按一定規(guī)則拼接,傳給上游服務(wù),然后在上游服務(wù)中按照規(guī)則將header解析出來(lái),skywalking通過(guò)分析,即可將上下游的span關(guān)聯(lián)起來(lái)。

func OnSnapshot() {// client := GetClinet()// 表示收到客戶端請(qǐng)求,因?yàn)橹蛔粉櫤笈_(tái)服務(wù)之間的鏈路,所以這里不需要提取context信息span2, ctx, err := tracer.CreateEntrySpan(context.Background(), "/API/Snapshot", func() (string, error){return "", nil})if err != nil {logs.Info("[Create Exit Span Error]: [%v]", err)return}span2.SetComponent(5200)// 表示rpc調(diào)用的span,這里需要向上游服務(wù)注入context信息,即參數(shù)中的headerreq := Req{3, ""}span1, err := tracer.CreateExitSpan(ctx, "/Service/OnSnapshot", "RTS_Server", func(header string) error{return req.Set(propagation.Header, header)})if err != nil {logs.Info("[Create Exit Span Error]: [%v]", err)return}span1.SetComponent(5200) // Golang程序使用范圍是[5000, 6000),還要在skywalking中配置,config目錄下的component-libraries.yml文件var res Res// rpc調(diào)用err = conn.Call("Req.Snapshot", req, &res)if err != nil {logs.Info("[RPC Call Snapshot Error]: [%v]", err)return} else {logs.Info("[RPC Call Snapshot Success]: [%s]", res)}span1.End()span2.End() // 一定要確保span被結(jié)束// s1 := ReportedSpan(span1)// s2 := ReportedSpan(span2)// spans := []go2sky.ReportedSpan{s1, s2}// r.Send(spans) }

?

? ? 2. Server端 (上游服務(wù))

? ? ? ? 定義請(qǐng)求信息的結(jié)構(gòu)體:

type ReqBody struct {A intHeader string }

? ? ? ? 定義context信息的提取方法:

func (p *ReqBody) Get(key string) string {subs := strings.Split(p.Header, ":")if len(subs) != 2 || subs[0] != key {return ""}return subs[1] }

? ? ? ? 創(chuàng)建reporter和tracer:

r, err = reporter.NewGRPCReporter("192.168.204.130:11800") if err != nil {logs.Info("[New GRPC Reporter Error]: [%v]\n", err)return }tracer, err = go2sky.NewTracer("Service_Test", go2sky.WithReporter(r), go2sky.WithInstance("Service_Test_1")) if err != nil {logs.Info("[New Tracer Error]: [%v]\n", err)return } tracer.WaitUntilRegister()

? ? ? ? 創(chuàng)建span:

? ? ? ? 在創(chuàng)建EntrySpan時(shí),調(diào)用Get()方法提取context信息

func (p *Req)Snapshot(req ReqBody, res *Res) error {// 表示收到 rpc 客戶端的請(qǐng)求,這里需要提取context信息span1, ctx, err := tracer.CreateEntrySpan(context.Background(), "/Service/OnSnapshot/QueringSnapshot", func() (string, error){return req.Get(propagation.Header), nil})if err != nil {logs.Info("[Create Exit Span Error]: [%v]\n", err)return err}span1.SetComponent(5200)// span1.SetPeer("Service_Test")// 表示去請(qǐng)求了一次數(shù)據(jù)庫(kù)span2, err := tracer.CreateExitSpan(ctx, "/database/QuerySnapshot", "APIService", func(header string) error {return nil})span2.SetComponent(5200)time.Sleep(time.Millisecond * 6)*res = "Return Snapshot Info"span2.End()span1.End()// s1 := ReportedSpan(span1)// s2 := ReportedSpan(span2)// spans := []go2sky.ReportedSpan{s1, s2}// r.Send(spans)return nil }

?

? ? 3. 結(jié)果展示?

? ? ? ? 鏈路追蹤:

? ? ? ??

? ? ? ? ?拓?fù)鋱D:

? ? ? ??

總結(jié)

以上是生活随笔為你收集整理的Go2sky -- Golang用skywalking实现全链路追踪的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。