日本熟妇hd丰满老熟妇,中文字幕一区二区三区在线不卡 ,亚洲成片在线观看,免费女同在线一区二区

通過ASM實現gRPC鏈路追蹤

可觀測鏈路OpenTelemetry版為分布式應用的開發者提供了完整的調用鏈路還原、調用請求量統計、鏈路拓撲、應用依賴分析等工具。本文介紹如何通過Headers在ASM實現gRPC鏈路追蹤。

前提條件

示例工程

gRPC的示例工程請參見hello-servicemesh-grpc,本文檔中提到的目錄都為hello-servicemesh-grpc下的目錄。

GRPC協議Headers編程實踐

服務端獲取Headers

  • 基本方法

    • 使用Java語言通過服務端獲取Headers實現基本方法。

      實現攔截器ServerInterceptor接口的interceptCall(ServerCall<ReqT, RespT> call,final Metadata m,ServerCallHandler<ReqT, RespT> h)方法,通過String v = m.get(k)獲取header信息,get方法入參類型為Metadata.Key<String>

    • 使用Go語言通過服務端獲取Headers實現基本方法。

      metadata.FromIncomingContext(ctx)(md MD, ok bool),MD是一個map[string][]string。

    • 使用NodeJS語言通過服務端獲取Headers實現基本方法。

      call.metadata.getMap(),返回值類型是[key: string]: MetadataValueMetadataValue類型定義為string/Buffer。

    • 使用Python語言通過服務端獲取Headers實現基本方法。

      context.invocation_metadata(),返回值類型為2-tuple數組,2-tuple的形式為('k','v'),使用m.key, m.value獲取鍵值對。

  • Unary RPC

    • 使用Java語言通過服務端獲取Headers實現Unary RPC。

      對Headers無感知。

    • 使用Go語言通過服務端獲取Headers實現Unary RPC。

      在方法中直接調用metadata.FromIncomingContext(ctx),上下文參數ctx來自Talk的入參。

    • 使用NodeJS語言通過服務端獲取Headers實現Unary RPC。

      在方法內直接調用call.metadata.getMap()。

    • 使用Python語言通過服務端獲取Headers實現Unary RPC。

      在方法內直接調用context.invocation_metadata()。

  • Server streaming RPC

    • 使用Java語言通過服務端獲取Headers實現Server streaming RPC。

      對Headers無感知。

    • 使用Go語言通過服務端獲取Headers實現Server streaming RPC。

      在方法中直接調用metadata.FromIncomingContext(ctx),上下文參數ctx從TalkOneAnswerMore的入參stream中獲取stream.Context()

    • 使用NodeJS語言通過服務端獲取Headers實現Server streaming RPC。

      在方法內直接調用call.metadata.getMap()。

    • 使用Python語言通過服務端獲取Headers實現Server streaming RPC。

      在方法內直接調用context.invocation_metadata()

  • Client streaming RPC

    • 使用Java語言通過服務端獲取Headers實現Client streaming RPC。

      對Headers無感知。

    • 使用Go語言通過服務端獲取Headers實現Client streaming RPC。

      在方法中直接調用metadata.FromIncomingContext(ctx),上下文參數ctx從TalkMoreAnswerOne的入參stream中獲取stream.Context()。

    • 使用NodeJS語言通過服務端獲取Headers實現Client streaming RPC。

      在方法內直接調用call.metadata.getMap()。

    • 使用Python語言通過服務端獲取Headers實現Client streaming RPC。

      在方法內直接調用context.invocation_metadata()。

  • Bidirectional streaming RPC

    • 使用Java語言通過服務端獲取Headers實現Bidirectional streaming RPC。

      對Headers無感知。

    • 使用Go語言通過服務端獲取Headers實現Bidirectional streaming RPC。

      在方法中直接調用metadata.FromIncomingContext(ctx),上下文參數ctx從TalkBidirectional的入參stream中獲取stream.Context()。

    • 使用NodeJS語言通過服務端獲取Headers實現Bidirectional streaming RPC。

      在方法內直接調用call.metadata.getMap()。

    • 使用Python語言通過服務端獲取Headers實現Bidirectional streaming RPC。

      在方法內直接調用context.invocation_metadata()。

客戶端發送Headers

  • 基本方法

    • 使用Java語言通過客戶端發送Headers實現基本方法。

      實現攔截器ClientInterceptor接口的interceptCall(MethodDescriptor<ReqT, RespT> m, CallOptions o, Channel c)方法,實現返回值類型ClientCall<ReqT, RespT>的start((Listener<RespT> l, Metadata h))方法,通過h.put(k, v)填充header信息,put方法入參k的類型為Metadata.Key<String>v的類型為String。

    • 使用Go語言通過客戶端發送Headers實現基本方法。

      metadata.AppendToOutgoingContext(ctx,kv ...) context.Context

    • 使用NodeJS語言通過客戶端發送Headers實現基本方法。

      metadata=call.metadata.getMap()metadata.add(key, headers[key])

    • 使用Python語言通過客戶端發送Headers實現基本方法。

      metadata_dict = {}變量填充metadata_dict[c.key] = c.value,最終轉為list tuple類型list(metadata_dict.items())。

  • Unary RPC

    • 使用Java語言通過客戶端發送Headers實現Unary RPC。

      對Headers無感知。

    • 使用Go語言通過客戶端發送Headers實現Unary RPC。

      在方法中直接調用metadata.AppendToOutgoingContext(ctx,kv)。

    • 使用NodeJS語言通過客戶端發送Headers實現Unary RPC。

      在方法內直接使用基本方法。

    • 使用Python語言通過客戶端發送Headers實現Unary RPC。

      在方法內直接使用基本方法。

  • Server streaming RPC

    • 使用Java語言通過客戶端發送Headers實現Server streaming RPC。

      對Headers無感知。

    • 使用Go語言通過客戶端發送Headers實現Server streaming RPC。

      在方法中直接調用metadata.AppendToOutgoingContext(ctx,kv)。

    • 使用NodeJS語言通過客戶端發送Headers實現Server streaming RPC。

      在方法內直接使用基本方法。

    • 使用Python語言通過客戶端發送Headers實現Server streaming RPC。

      在方法內直接使用基本方法。

  • Client streaming RPC

    • 使用Java語言通過客戶端發送Headers實現Client streaming RPC。

      對Headers無感知。

    • 使用Go語言通過客戶端發送Headers實現Client streaming RPC。

      在方法中直接調用metadata.AppendToOutgoingContext(ctx,kv)。

    • 使用NodeJS語言通過客戶端發送Headers實現Client streaming RPC。

      在方法內直接使用基本方法。

    • 使用Python語言通過客戶端發送Headers實現Client streaming RPC。

      在方法內直接使用基本方法。

  • Bidirectional streaming RPC

    • 使用Java語言通過客戶端發送Headers實現Bidirectional streaming RPC。

      對Headers無感知。

    • 使用Go語言通過客戶端發送Headers實現Bidirectional streaming RPC。

      在方法中直接調用metadata.AppendToOutgoingContext(ctx,kv)。

    • 使用NodeJS語言通過客戶端發送Headers實現Bidirectional streaming RPC。

      在方法內直接使用基本方法。

    • 使用Python語言通過客戶端發送Headers實現Bidirectional streaming RPC。

      在方法內直接使用基本方法。

propagate Headers

由于鏈路追蹤需要將上游傳遞過來的鏈路元數據透傳給下游,以形成同一條請求鏈路的完整信息,需要將服務端獲取的Headers信息中,和鏈路追蹤相關的Headers透傳給向下游發起請求的客戶端。

除了Java語言的實現,其他語言的通信模型方法都對Headers有感知,因此可以將服務端讀取Headers-傳遞Headers-客戶端發送Headers這三個動作有順序地在4種通信模型方法內部實現。

Java語言讀取和寫入Headers是通過兩個攔截器分別實現的,因此propagate Headers無法在一個順序的流程里實現,且考慮到并發因素,以及只有讀取攔截器知道鏈路追蹤的唯一ID,所以無法通過最直覺的緩存方式搭建兩個攔截器的橋梁。

Java語言的實現提供了一種Metadata-Context Propagation的機制。機制

在服務器攔截器讀取階段,通過ctx.withValue(key, metadata)Metadata/Header存入Context,其中Key是Context.Key<String>類型。然后在客戶端攔截器中,通過key.get()Metadata從Context讀出,get方法默認使用Context.current()上下文,這就保證了一次請求的Headers讀取和寫入使用的是同一個上下文。

有了propagate Headers的實現,基于GRPC的鏈路追蹤就有了機制上的保證。

部署和驗證網格拓撲

實現gRPC鏈路追蹤之前,您需要部署和驗證網格拓撲,確保網格拓撲是可以通信的。

進入示例工程的tracing目錄,該目錄下包含4種編程語言的部署腳本。以下以Go版本為例,部署和驗證網格拓撲。

cd go
# 部署
sh apply.sh
# 驗證
sh test.sh

如果沒有出現異常信息,則說明網格拓撲可以正常通信。

部署后的服務網格拓撲如下圖所示。網絡拓撲

鏈路追蹤

  1. 將鏈路追蹤數據采集到阿里云可觀測鏈路OpenTelemetry版。具體操作,請參見將鏈路追蹤數據采集到阿里云可觀測鏈路OpenTelemetry版。

  2. 登錄可觀測鏈路OpenTelemetry版,在左側導航欄,單擊鏈路入口。

  3. 鏈路入口頁面,單擊目標應用的應用拓撲。

    可以看到完整的鏈路,包括本地請求端-Ingressgateway-grpc-server-svc1-grpc-server-svc2-grpc-server-svc3。鏈路追蹤

  4. 全鏈路聚合頁面,單擊全鏈路聚合頁簽,查看全鏈路聚合。

    全鏈路聚合
  5. 全鏈路聚合頁簽,單擊Span名稱下的鏈路,查看調用鏈路。

    調用鏈路