精品一区二区三区在线成人,欧美精产国品一二三区,Ji大巴进入女人66h,亚洲春色在线视频

在多語言的分布式系統中如何傳遞 Trace 信息

云計算 分布式
在解決這個問題之前想要搞清楚 Trace 是如何跨語言以及跨應用傳遞的。其實也可以類比為在分布式系統中如何傳遞上下文;既然要傳遞數據那就涉及到系統之間的調用,也就是我們常說的?RPC(remote procedure call)。

背景

圖片圖片

圖片圖片

圖片圖片

前段時間有朋友問我關于 spring cloud 的應用在調用到 Go 的 API 之后出現 Trace 沒有串聯起來的問題。

完整的調用流程如下:

┌──────┐             
│Client│             
└┬─────┘             
┌▽──────────────────┐
│SpringCloud GateWay│
└┬──────────────────┘
┌▽──────────────┐    
│SpringBoot(app)│    
└┬──────────────┘    
┌▽──────────┐        
│Feign(http)│        
└┬──────────┘        
┌▽─────┐             
│Go Gin│             
└──────┘

根因

在解決這個問題之前想要搞清楚 Trace 是如何跨語言以及跨應用傳遞的。

其實也可以類比為在分布式系統中如何傳遞上下文;既然要傳遞數據那就涉及到系統之間的調用,也就是我們常說的 RPC(remote procedure call)。

提到 PRC 我們常見的一般有兩種協議:

? 基于 HTTP 協議,簡單易讀,兼容性好

? 基于 TCP 的私有協議,高效性能更佳

基于 TCP 私有協議的又誕生出許多流行的框架,比如:

? Dubbo

? Thrift

? gRPC(基于 HTTP2,嚴格來說不算私有協議)

? 基于 MQ 實現的 RPC(生產消費者模式,本質上這些 MQ 都是私有協議,比如 RocketMQ、Pulsar 等)

但我們需要在 RPC 調用的過程中在上下文里包含 Trace 時,通常都是將 TraceId 作為元數據進行傳遞。

對于 HTTP 來說就是 header、而其余的私有 TCP 協議通常也會提供一個元數據的結構用于存放一些非業務數據。

圖片圖片

圖片圖片

圖片圖片

比如在 OpenTelemetry-Go 的 sdk 中,會在一次 RPC 中對 Trace 數據進行埋點。

最終也是使用 metadata metadata.MD 來獲取上下文。

在 Pulsar 中是將 TraceId 存放在 properties 中,也相當于是元數據。

┌──────┐
│Client│
└┬─────┘
┌▽─────┐
│Pulsar│
└┬─────┘
┌▽───┐  
│gRPC│  
└────┘
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {  
    defer apiCounter.Add(ctx, 1)  
    md, _ := metadata.FromIncomingContext(ctx)  
    log.Printf("Received: %v, md: %v", in.GetName(), md)  
    name, _ := os.Hostname()  
    span := trace.SpanFromContext(ctx)  
    span.SetAttributes(attribute.String("request.name", in.Name))  
    s.span(ctx)  
    return &pb.HelloReply{Message: fmt.Sprintf("hostname:%s, in:%s, md:%v", name, in.Name, md)}, nil  
}

圖片圖片

圖片圖片

在這樣一次調用中如果我們將 Pulsar 的 properties 和 gRPC meta 打印出來將會看到 TraceID 是如何進行傳遞的。

解決

回到這個問題本身,Trace 在 Gin Server 端沒有關聯起來,明顯就是 Gin 沒有接收到上游的 TraceId,導致它認為是新的一次調用,從而會創建一個 Trace。

解決起來也很容易,只需要在啟動 Gin 的時候傳入一個 OTEL 提供的攔截器,在這個攔截器中 OTEL 的 sdk 會自動從 HTTP header 里解析出 TraceId 然后塞入到當前的 context 中,這樣兩個進程的 Trace 就可以關聯起來了。

相關代碼如下:

r := gin.New()
    r.Use(otelgin.Middleware("my-server"))

由于 Go 沒有提供類似于 Java 的 javaagent 擴展,這類原本可以全自動打樁的代碼都需要硬編碼實現。

在這個 otelgin 實現的 Middleware 里會使用 HTTP header 來傳輸 context。

圖片圖片

圖片圖片

圖片圖片

本質上是操作 HTTP header 查詢和寫入 Trace

圖片圖片

會首先獲取上游的 TraceID,這里的 traceparentHeader 也就是我們剛才看到的 traceparent。

如果獲取到了就會解析里面的 TraceID,并生成當前的 Context,這樣這個 context 就會一直往后傳遞了。

流程與上文提到 gRPC 類似。

image.pngimage.png

這是目前 otel-go-sdk 支持的自動打樁框架[1],目前看來還不太多,但常用的也都支持了。

總結

如何跨進程調的 Trace 信息都是通過網絡傳遞的,只是對于不同的協議傳輸的細節也各不相同,但原理都是類似的。

圖片圖片

關鍵就是上面這兩張圖,進程 1 在調用進程 2 的時候將信息寫入進去,進程 2 在收到請求的時候解析出 Trace,這兩個步驟缺一不可。#Blog

引用鏈接

[1] 自動打樁框架: https://github.com/open-telemetry/opentelemetry-go-contrib/tree/main/instrumentation

責任編輯:武曉燕 來源: crossoverJie
相關推薦

2012-04-19 11:40:21

Titanium

2024-01-12 10:01:07

框架編程

2022-08-09 07:22:15

語言數據庫程序

2024-03-19 11:41:12

2023-05-12 08:23:03

分布式系統網絡

2014-07-09 09:20:06

WPFWPF應用

2025-07-24 07:42:08

2014-04-16 14:50:20

Spark

2024-10-18 08:00:00

分布式系統背壓數據庫

2022-05-05 12:03:08

分布式系統設計

2023-07-19 08:22:01

分布式系統數據

2023-02-11 00:04:17

分布式系統安全

2018-12-14 10:06:22

緩存分布式系統

2022-03-15 09:10:00

分布式訓練實踐

2020-03-12 10:25:06

解決分布式系統幽靈復現

2023-05-29 14:07:00

Zuul網關系統

2022-05-11 13:55:18

高可用性分布式彈性

2016-08-12 15:17:40

分布式

2024-07-05 08:26:54

2022-04-14 10:24:27

分布式系統性能
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 沛县| 洛浦县| 百色市| 依兰县| 高台县| 塘沽区| 虎林市| 双辽市| 新晃| 平果县| 宕昌县| 桓台县| 平遥县| 安仁县| 陆良县| 贺兰县| 佛坪县| 巫溪县| 沂水县| 武胜县| 乐安县| 本溪市| 台安县| 易门县| 昌图县| 石嘴山市| 聂拉木县| 修武县| 凉城县| 德保县| 喀喇| 郓城县| 棋牌| 托克托县| 五华县| 桐梓县| 申扎县| 河西区| 平罗县| 礼泉县| 永城市|