首頁 > 後端開發 > Golang > 主體

使用 OpenTelemetry 統一不同服務的範圍

WBOY
發布: 2024-02-13 23:00:11
轉載
480 人瀏覽過

使用 OpenTelemetry 统一不同服务的范围

php小編小新今天為大家介紹一個強大的工具-OpenTelemetry,它可以幫助開發者在不同的服務中實現統一的範圍管理。在現代的分散式系統中,應用程式通常由多個微服務組成,每個微服務都有自己的日誌、指標和追蹤資訊。 OpenTelemetry提供了一種簡單而強大的方式來整合和管理這些訊息,使得開發者能夠更好地理解和調試整個系統的性能和行為。無論是在本地開發環境還是在生產環境中,OpenTelemetry都能幫助開發者更好地理解和優化他們的應用程式。

問題內容

我剛開始使用 opentelemetry,並為此創建了兩個(微)服務:standardgeomap

最終用戶向standard服務發送請求,後者會向geomap發送請求以獲取訊息,然後再將結果傳回給最終用戶。我使用 grpc 進行所有通訊。

我已經對我的功能進行了這樣的檢測:

對於標準

type standardservice struct {
    pb.unimplementedstandardserviceserver
}

func (s *standardservice) getstandard(ctx context.context, in *pb.getstandardrequest) (*pb.getstandardresponse, error) {

    conn, _:= createclient(ctx, geomapsvcaddr)
    defer conn1.close()

    newctx, span1 := otel.tracer(name).start(ctx, "getstandard")
    defer span1.end()

    countryinfo, err := pb.newgeomapserviceclient(conn).getcountry(newctx,
        &pb.getcountryrequest{
            name: in.name,
        })

    //...

    return &pb.getstandardresponse{
        standard: standard,
    }, nil

}

func createclient(ctx context.context, svcaddr string) (*grpc.clientconn, error) {
    return grpc.dialcontext(ctx, svcaddr,
        grpc.withtransportcredentials(insecure.newcredentials()),
        grpc.withunaryinterceptor(otelgrpc.unaryclientinterceptor()),
    )
}
登入後複製

對於地理地圖

type geomapservice struct {
    pb.unimplementedgeomapserviceserver
}

func (s *geomapservice) getcountry(ctx context.context, in *pb.getcountryrequest) (*pb.getcountryresponse, error) {

    _, span := otel.tracer(name).start(ctx, "getcountry")
    defer span.end()

    span.setattributes(attribute.string("country", in.name))

    span.addevent("retrieving country info")

    //...
    
    span.addevent("country info retrieved")

    return &pb.getcountryresponse{
        country: &country,
    }, nil

}
登入後複製

這兩個服務都配置為將其跨度發送到 jaeger 後端並共享幾乎相同的主要功能(評論中指出了細微的差異):

const (
    name        = "mapedia"
    service     = "geomap" //or standard
    environment = "production"
    id          = 1
)

func tracerProvider(url string) (*tracesdk.TracerProvider, error) {
    // Create the Jaeger exporter
    exp, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(url)))
    if err != nil {
        return nil, err
    }
    tp := tracesdk.NewTracerProvider(
        // Always be sure to batch in production.
        tracesdk.WithBatcher(exp),
        // Record information about this application in a Resource.
        tracesdk.WithResource(resource.NewWithAttributes(
            semconv.SchemaURL,
            semconv.ServiceName(service),
            attribute.String("environment", environment),
            attribute.Int64("ID", id),
        )),
    )
    return tp, nil
}

func main() {

    tp, err := tracerProvider("http://localhost:14268/api/traces")
    if err != nil {
        log.Fatal(err)
    }

    defer func() {
        if err := tp.Shutdown(context.Background()); err != nil {
            log.Fatal(err)
        }
    }()
    otel.SetTracerProvider(tp)

    listener, err := net.Listen("tcp", ":"+port)
    if err != nil {
        panic(err)
    }

    s := grpc.NewServer(
        grpc.UnaryInterceptor(otelgrpc.UnaryServerInterceptor()),
    )
    reflection.Register(s)
    pb.RegisterGeoMapServiceServer(s, &geomapService{}) // or pb.RegisterStandardServiceServer(s, &standardService{})
    if err := s.Serve(listener); err != nil {
        log.Fatalf("Failed to serve: %v", err)
    }
}
登入後複製

當我查看最終用戶對標準服務的請求產生的追蹤時,我可以看到它正如預期的那樣,調用其geomap服務:

但是,我沒有看到已新增至子範圍的任何屬性或事件(我在偵測geomap< 的< 的 getcountry 函數時新增了一個屬性和2 個事件/em>) 。

然而,我注意到這些屬性在另一個單獨的追蹤中可用(在 jaeger 中的「geomap」服務下可用),其跨度 id 與標準服務中的子跨度完全無關:

現在我期望的是有一個跟踪,並查看與 標準 範圍內的子範圍中的 geomap 相關的所有屬性/事件。如何從這裡得到預期的結果?

解決方法

跨度上下文(包含追蹤id 和跨度id,如「service instrumentation & 中所述)術語")應該從父跨度傳播到子跨度,以便它們成為同一跟踪的一部分。

使用 opentelemetry,這通常是透過使用為各種庫(包括 grpc)提供的插件來檢測程式碼來自動完成的。
但是,在您的情況下,傳播似乎無法正常工作。

在您的程式碼中,您將在getstandard 函數中啟動一個新範圍,然後在發出getcountry 請求時使用該上下文(newctx) 。這是正確的,因為新上下文應該包含父跨度的跨度上下文 (getstandard)。
但問題可能與您的 createclient 函數有關:

func createclient(ctx context.context, svcaddr string) (*grpc.clientconn, error) {
    return grpc.dialcontext(ctx, svcaddr,
        grpc.withtransportcredentials(insecure.newcredentials()),
        grpc.withunaryinterceptor(otelgrpc.unaryclientinterceptor()),
    )
}
登入後複製

您正確使用了otelgrpc.unaryclientinterceptor 在這裡,這應該確保上下文正確傳播,但不清楚何時調用此函數。如果在呼叫 getstandard 函數之前呼叫它,則用於建立客戶端的上下文將包含來自 getstandard 的跨度上下文。

為了進行測試,請嘗試確保在呼叫 getstandard 函數之後建立用戶端,並且在整個請求中使用相同的上下文。

您可以透過將 newctx 直接傳遞給 getcountry 函數來完成此操作,如 getstandard 函數的修改版本所示:

func (s *standardservice) getstandard(ctx context.context, in *pb.getstandardrequest) (*pb.getstandardresponse, error) {
    newctx, span1 := otel.tracer(name).start(ctx, "getstandard")
    defer span1.end()

    conn, _:= createclient(newctx, geomapsvcaddr)
    defer conn.close()

    countryinfo, err := pb.newgeomapserviceclient(conn).getcountry(newctx,
        &pb.getcountryrequest{
            name: in.name,
        })

    //...

    return &pb.getstandardresponse{
        standard: standard,
    }, nil
}
登入後複製

現在,用於建立客戶端並發出 getcountry 請求的上下文將包括來自 getstandard 的跨度上下文,並且它們應作為 jaeger 中同一追蹤的一部分出現。

(一如既往,請檢查 createclientgetcountry 等函數傳回的錯誤,為簡潔起見,此處未顯示)。

此外:

  • 另請檢查您的傳播器:確保您使用相同的上下文傳播器 在這兩個服務中,最好是w3c tracecontextpropagator,這是opentelemetry中預設的。

    您可以如下明確設定傳播器:

    otel.settextmappropagator(propagation.tracecontext{})
    
    登入後複製

    將以上行加入到兩個服務中 main 函數的開頭。

  • 確保傳遞元資料:grpc 攔截器應自動從請求的元資料中註入/提取追蹤上下文,但要仔細檢查以確保其正常運作。

    getcountry 函數中啟動跨度後,您可以記錄追蹤 id 和跨度 id:

    ctx, span := otel.tracer(name).start(ctx, "getcountry")
    sc := trace.spancontextfromcontext(ctx)
    log.printf("trace id: %s, span id: %s", sc.traceid(), sc.spanid())
    defer span.end()
    
    登入後複製

    并在 getstandard 函数中执行相同的操作:

    newCtx, span1 := otel.Tracer(name).Start(ctx, "GetStandard")
    sc := trace.SpanContextFromContext(newCtx)
    log.Printf("Trace ID: %s, Span ID: %s", sc.TraceID(), sc.SpanID())
    defer span1.End()
    
    登入後複製

    如果上下文正确传播,两个服务中的跟踪 id 应该匹配。

    以上是使用 OpenTelemetry 統一不同服務的範圍的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:stackoverflow.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板