微服務應用程式中的分散式追蹤

Last reviewed 2024-06-26 UTC

本文是四部曲系列文章的第四篇,主題是設計、建構及部署微服務。本系列文章將說明微服務架構的各種元素。本系列文章將說明微服務架構模式的優點和缺點,以及如何應用這項模式。

  1. 微服務簡介
  2. 將單體式應用程式重構為微服務
  3. 微服務設定中的服務間通訊
  4. 微服務應用程式中的分散式追蹤 (本文)

本系列文章適用於設計及實作遷移作業的應用程式開發人員和架構師,以便將單體應用程式重構為微服務應用程式。

在分散式系統中,請務必瞭解要求如何從一個服務流向另一個服務,以及在每個服務中執行工作需要多長時間。請參考上一個文件中部署的微服務式線上選品店應用程式,將單體式應用程式重構為微服務。應用程式由多項服務組成。舉例來說,下圖顯示產品詳細資料頁面,可從前端、推薦和廣告服務擷取資訊。

產品詳細資料頁面。

如要轉譯產品詳細資料頁面,前端服務會與推薦服務和廣告服務通訊,如下圖所示:

前端服務會與推薦服務、產品目錄和廣告服務通訊。

圖 1. 以不同語言編寫的服務。

在圖 1 中,前端服務是使用 Go 編寫。推薦服務則是使用 Python 編寫,並使用 gRPC 與前端服務通訊。以 Java 編寫的廣告服務也會使用 gRPC 與前端服務通訊。除了 gRPC,服務間通訊方法也可以是 REST HTTP。

建構這類分散式系統時,您希望可視性工具提供下列洞察資料:

  • 要求經過的服務。
  • 要求速度緩慢時,延遲情形發生的位置。
  • 要求失敗時發生錯誤。
  • 要求的執行方式與系統的正常行為有何不同。
  • 要求執行作業的差異是否與效能相關 (某些服務呼叫是否比平常花費較多或較少的時間)。

目標

  • 使用 kustomize 資訊清單檔案設定基礎架構。
  • 將 Online Boutique 範例應用程式部署至 Google Kubernetes Engine (GKE)。
  • 使用 Cloud Trace 查看範例應用程式中的使用者歷程。

費用

在本文件中,您會使用 Google Cloud的下列計費元件:

您可以使用 Pricing Calculator 根據預測用量產生預估費用。 新 Google Cloud 使用者可能符合申請免費試用的資格。

完成這份文件後,您可以刪除已建立的資源,避免繼續產生費用。詳情請參閱「清除所用資源」一節。

事前準備

如果您已完成本系列先前文件的說明,在微服務設定中進行跨服務通訊,即可重複使用該專案。完成下列步驟即可啟用其他 API 並設定環境變數。

  1. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  2. Make sure that billing is enabled for your Google Cloud project.

  3. In the Google Cloud console, activate Cloud Shell.

    Activate Cloud Shell

  4. 啟用 Compute Engine、GKE、Cloud SQL、Artifact Analysis、Trace 和 Container Registry 的 API:

     gcloud services enable \
       compute.googleapis.com \
       sql-component.googleapis.com \
       servicenetworking.googleapis.com\
       container.googleapis.com \
       containeranalysis.googleapis.com \
       containerregistry.googleapis.com \
       sqladmin.googleapis.com
    

分散式追蹤記錄

分散式追蹤會將內容相關中繼資料附加至每個要求,並確保在要求之間共用中繼資料。您可以使用追蹤點來檢測分散式追蹤。舉例來說,您可以使用兩個追蹤點來檢測服務 (前端、推薦內容和廣告),以便處理用戶端要求,查看產品詳細資料:一個追蹤點用於傳送要求,另一個追蹤點用於接收回應。下圖顯示此追蹤點檢測功能的運作方式:

具有兩個追蹤點的追蹤點檢測功能。

圖 2:每個跨服務呼叫都有兩個追蹤點,其中包含要求-回應配對。

為了讓追蹤點瞭解在服務叫用時要執行哪項要求,來源服務會沿著執行流程傳遞 追蹤 ID。傳遞追蹤 ID 的程序稱為「中繼資料傳播」或「分散式內容傳播」。當分散式應用程式的服務在執行特定要求期間彼此通訊時,情境傳播會透過網路呼叫傳輸中繼資料。下圖顯示結構描述元傳播方式:

中繼資料傳播會傳遞追蹤 ID。

圖 3:追蹤中繼資料會在服務之間傳遞。中繼資料包含哪些服務呼叫哪些服務,以及時間戳記等資訊。

在線上精品店範例中,當使用者傳送擷取產品詳細資料的初始要求時,追蹤記錄就會開始。系統會產生新的追蹤 ID,並為每個後續要求加上標頭,其中包含回傳至原始要求的背景資訊中繼資料。

為了滿足使用者要求而叫用的每個個別作業稱為「span」。原始服務標記的每個區間都有專屬的 ID 和父區間的追蹤 ID。下圖顯示追蹤記錄的甘特圖示意圖:

個別作業會標記為跨度。

圖 4:父項範圍會納入子項範圍的回應時間。

圖 4 顯示追蹤樹狀圖,其中前端服務會呼叫推薦服務和廣告服務。前端服務是父項區間,可說明使用者觀察到的回應時間。子區間會說明推薦服務和廣告服務的呼叫方式和回應方式,包括回應時間資訊。

Istio 等服務網格可讓您分散追蹤服務對服務流量,無須任何專屬檢測工具。不過,在某些情況下,您可能需要進一步控管追蹤記錄,或是需要追蹤不在服務網狀結構中執行的程式碼。

本文會使用 OpenTelemetry 啟用分散式微服務應用程式的檢測功能,以便收集追蹤記錄和指標。OpenTelemetry 可讓您收集指標和追蹤記錄,然後匯出至後端,例如 Prometheus、Cloud Monitoring、Datadog、Graphite、Zipkin 和 Jaeger。

使用 OpenTelemetry 進行檢測

以下各節說明如何使用內容傳播功能,讓多個要求的跨度附加至單一父項追蹤記錄。

這個範例使用 OpenTelemetry 的 JavascriptPythonGo 程式庫,為付款、推薦和前端服務的實作項目記錄追蹤記錄。視檢測工具的詳細程度而定,追蹤資料可能會影響專案的費用 (Cloud Trace 計費)。為降低成本問題,大多數追蹤系統都會採用各種形式的取樣,只擷取觀察到的追蹤記錄的特定百分比。在實際工作環境中,貴機構可能會基於某些原因,決定要取樣哪些資料,您可以根據成本管理、著重於有興趣的追蹤記錄或篩除雜訊,自訂取樣策略。如要進一步瞭解取樣,請參閱「OpenTelemetry 取樣」。

本文件使用「Trace」Trace來呈現分散式追蹤記錄。您可以使用 OpenTelemetry 匯出工具,將追蹤記錄傳送至 Trace。

註冊追蹤記錄匯出工具

本節將說明如何在微服務程式碼中新增行,以便在各服務中註冊追蹤匯出工具。

針對前端服務 (以 Go 編寫),以下程式碼範例會註冊匯出程式:

[...]
exporter, err := otlptracegrpc.New(
        ctx,
        otlptracegrpc.WithGRPCConn(svc.collectorConn))
    if err != nil {
        log.Warnf("warn: Failed to create trace exporter: %v", err)
    }
tp := sdktrace.NewTracerProvider(
        sdktrace.WithBatcher(exporter),
        sdktrace.WithSampler(sdktrace.AlwaysSample()))
    otel.SetTracerProvider(tp)

針對以 Python 編寫的推薦服務,下列程式碼範例會註冊匯出程式:

if os.environ["ENABLE_TRACING"] == "1":
    trace.set_tracer_provider(TracerProvider())
    otel_endpoint = os.getenv("COLLECTOR_SERVICE_ADDR", "localhost:4317")
    trace.get_tracer_provider().add_span_processor(
        BatchSpanProcessor(
            OTLPSpanExporter(
            endpoint = otel_endpoint,
            insecure = True
            )
        )
    )

針對以 JavaScript 編寫的付款服務,下列程式碼範例會註冊匯出程式:

provider.addSpanProcessor(new SimpleSpanProcessor(new OTLPTraceExporter({url: collectorUrl})));
provider.register();

設定背景資訊傳播

追蹤系統必須遵循追蹤內容規格,該規格會定義在服務之間傳播追蹤內容的格式。傳播格式範例包括 Zipkin 的 B3 格式X-Google-Cloud-Trace

OpenTelemetry 會使用全域 TextMapPropagator 傳播內容。這個範例使用追蹤記錄脈絡傳播器,該工具採用 W3C 追蹤記錄格式。檢測程式庫 (例如 OpenTelemetry 的 HTTP 和 gRPC 程式庫) 會使用全域傳播器,將追蹤內容做為中繼資料新增至 HTTP 或 gRPC 要求。如要成功進行內容傳播,用戶端和伺服器必須使用相同的傳播格式。

透過 HTTP 傳播內容

前端服務會將追蹤結構定義插入 HTTP 要求標頭。後端服務會擷取追蹤記錄內容。以下程式碼範例說明如何檢測前端服務,以便設定追蹤內容:

otel.SetTextMapPropagator(
    propagation.NewCompositeTextMapPropagator(
        propagation.TraceContext{}, propagation.Baggage{}))

if os.Getenv("ENABLE_TRACING") == "1" {
    log.Info("Tracing enabled.")
    initTracing(log, ctx, svc)
} else {
    log.Info("Tracing disabled.")
}

...

var handler http.Handler = r
handler = &logHandler{log: log, next: handler}     // add logging
handler = ensureSessionID(handler)                 // add session ID
handler = otelhttp.NewHandler(handler, "frontend") // add OpenTelemetry tracing

透過 gRPC 傳播背景資訊

請考慮結帳服務根據使用者選取的產品下單的流程。這些服務會透過 gRPC 通訊。

以下程式碼範例使用 gRPC 呼叫攔截器,可攔截傳出呼叫並插入追蹤記錄:

var srv *grpc.Server

// Propagate trace context always
otel.SetTextMapPropagator(
    propagation.NewCompositeTextMapPropagator(
        propagation.TraceContext{}, propagation.Baggage{}))
srv = grpc.NewServer(
    grpc.UnaryInterceptor(otelgrpc.UnaryServerInterceptor()),
    grpc.StreamInterceptor(otelgrpc.StreamServerInterceptor()),
)

收到要求後,付款或產品目錄服務 (ListProducts) 會從要求標頭擷取背景資訊,並使用父追蹤記錄中繼資料產生子區段。

以下各節將詳細說明如何為線上精品店應用程式範例設定及查看分散式追蹤記錄。

部署應用程式

如果您已完成本系列先前文件 (微服務設定中的服務間通訊),並已啟動應用程式,請跳至下一節「查看追蹤記錄」。否則,請完成下列步驟,部署線上精品店範例:

  1. 如要設定基礎架構,請在 Cloud Shell 中複製 GitHub 存放區:

    git clone https://github.com/GoogleCloudPlatform/microservices-demo.git
    
  2. 針對新的部署作業,請重設環境變數:

    PROJECT_ID=PROJECT_ID
    REGION=us-central1
    GSA_NAME=microservices-sa
    GSA_EMAIL=$GSA_NAME@$PROJECT_ID.iam.gserviceaccount.com
    

    PROJECT_ID 替換為您要使用的Google Cloud 專案 ID。

  3. 選用:建立新叢集或重複使用現有叢集 (如果有的話):

    gcloud container clusters create-auto online-boutique --project=${PROJECT_ID}
      --region=${REGION}
    
  4. 建立 Google 服務帳戶:

    gcloud iam service-accounts create $GSA_NAME \
      --project=$PROJECT_ID
    
  5. 啟用 API:

    gcloud services enable \
    monitoring.googleapis.com \
    cloudtrace.googleapis.com \
    cloudprofiler.googleapis.com \
      --project ${PROJECT_ID}
    
  6. 將 Cloud Trace 所需的角色授予服務帳戶:

    gcloud projects add-iam-policy-binding ${PROJECT_ID} \
    --member "serviceAccount:${GSA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com" \
    --role roles/cloudtrace.agent
    
    gcloud projects add-iam-policy-binding ${PROJECT_ID} \
    --member "serviceAccount:${GSA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com" \
    --role roles/monitoring.metricWriter
    
    gcloud projects add-iam-policy-binding ${PROJECT_ID} \
    --member "serviceAccount:${GSA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com" \
    --role roles/cloudprofiler.agent
    
    gcloud iam service-accounts add-iam-policy-binding ${GSA_EMAIL} \
    --role roles/iam.workloadIdentityUser \
    --member "serviceAccount:${PROJECT_ID}.svc.id.goog[default/default]"
    
  7. 為 Kubernetes 服務帳戶 (default/default 為預設命名空間) 加上註解,以便使用身分與存取權管理 (IAM) 服務帳戶:

    kubectl annotate serviceaccount default \
        iam.gke.io/gcp-service-account=${GSA_EMAIL}
    
  8. 為 GKE 設定啟用 Google Cloud 觀測功能,以便啟用追蹤功能:

    cd ~/microservices-demo/kustomize && \
    kustomize edit add component components/google-cloud-operations
    

    上述指令會更新 kustomize/kustomization.yaml 檔案,內容如下所示:

    apiVersion: kustomize.config.k8s.io/v1beta1
    kind: Kustomization
    resources:
    - base
    components:
    - components/google-cloud-operations
    [...]
    
  9. 部署微服務:

    kubectl apply -k .
    
  10. 檢查部署狀態:

    kubectl rollout status deployment/frontend
    kubectl rollout status deployment/paymentservice
    kubectl rollout status deployment/recommendationservice
    kubectl rollout status deployment/adservice
    

    各指令的輸出內容如下所示:

    Waiting for deployment "" rollout to finish: 0 of 1 updated replicas are available...
    deployment "" successfully rolled out
    
  11. 取得已部署應用程式的 IP 位址:

    kubectl get service frontend-external | awk '{print $4}'
    

    等待負載平衡器的 IP 位址發布。如要退出指令,請按下 Ctrl+C。請記下負載平衡器的 IP 位址,然後透過網址 http://IP_ADDRESS 存取應用程式。負載平衡器可能需要一些時間才能恢復健康狀態,並開始傳送流量。

使用 Cloud Trace 查看追蹤記錄

使用者在 Online Boutique 應用程式中的購物歷程如下:

  • 使用者會在到達網頁上看到產品目錄。
  • 如要購買,使用者只要按一下「購買」即可。
  • 系統會將使用者重新導向至產品詳細資料頁面,讓他們將商品加入購物車。
  • 系統會將使用者重新導向至結帳頁面,讓他們付款並完成訂單。

請考慮以下情境:您需要排解載入產品詳細資料頁面時的長回應時間。如先前所述,產品詳細資料頁面由多個微服務組成。如要判斷發生高延遲的時間點和原因,您可以查看分散式追蹤圖表,瞭解不同服務中整個要求的效能。

如要查看分散式追蹤圖表,請按照下列步驟操作:

  1. 開啟應用程式,然後點選任一產品。系統會顯示產品詳細資料頁面。
  2. 前往 Google Cloud 控制台的「Trace list」頁面,查看時間軸。
  3. 如要查看分散式追蹤記錄結果,請按一下 URI 欄中的「Frontend」
  4. 「Trace Waterfall View」會顯示與 URI 相關聯的時距:

    「Trace Waterfall View」會顯示跨度。

    在上圖中,產品的追蹤記錄包含下列跨度:

    • 前端跨度會擷取用戶端在載入產品詳細資料頁面時觀察到的端對端延遲時間 (150.349 毫秒)。
    • 「推薦服務」區間會擷取產品相關推薦內容的後端擷取延遲時間 (4.246 毫秒)。
    • 廣告服務區間會擷取與產品頁面相關的廣告擷取後端呼叫延遲時間 (4.511 毫秒)。

如要排解回應時間過長的問題,您可以查看洞察資料,當服務的依附元件未達到服務等級目標 (SLO) 時,這類資料會顯示任何異常要求的延遲時間分布圖表。您也可以使用 Cloud Trace 取得效能深入分析結果,並根據取樣的資料建立分析報表

疑難排解

如果應用程式效能管理中沒有顯示追蹤記錄,請檢查記錄檔探索工具是否出現權限遭拒的錯誤。當服務帳戶沒有匯出記錄的權限時,就會發生權限遭拒的情況。請詳閱授予 Cloud Trace 所需角色的步驟,並務必使用正確的命名空間為服務帳戶加上註解。之後,請重新啟動 opentelemetrycollector

  kubectl rollout restart deployment opentelemetrycollector

清除所用資源

如要避免系統向您的 Google Cloud 帳戶收取本教學課程所用資源的費用,請刪除含有相關資源的專案,或者保留專案但刪除個別資源。

刪除專案

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

刪除資源

如果您想保留在本文件中使用的 Google Cloud 專案,請刪除個別資源:

  • 在 Cloud Shell 中刪除資源:

    gcloud container clusters delete online-boutique --project=${PROJECT_ID} --region=${REGION}
    

後續步驟