工作流程的最佳做法

使用 Workflows 協調服務時,可以參考這裡列出的最佳做法。

這份清單僅列舉部分建議,並未涵蓋所有情況,也不會教您使用工作流程的基本知識。本文假設您已大致瞭解整體 Google Cloud 情況和 Workflows。詳情請參閱「Google Cloud 架構完善的架構」和「工作流程總覽」。

選取最佳通訊模式

設計微服務架構來部署多項服務時,您可以從下列通訊模式中選取:

  • 服務對服務的直接通訊

  • 間接事件導向通訊 (也稱為「編舞」)

  • 自動設定、協調及管理 (也稱為「自動化調度管理」)

請務必考量上述各選項的優缺點,並為您的用途選取最佳模式。舉例來說,直接的服務對服務通訊可能比其他選項更容易實作,但會緊密連結您的服務。相較之下,事件導向架構可讓您鬆耦合服務,但監控和偵錯作業可能會更加複雜。最後,雖然 Workflows 等中央自動化調度管理工具的彈性較低,但可讓您協調服務間的通訊,不必像直接服務間通訊那樣緊密耦合,也不必像編排事件那樣複雜。

您也可以合併通訊模式。舉例來說,在事件驅動的協調流程中,密切相關的服務會在由事件觸發的協調流程中進行管理。同樣地,您可能會設計一個系統,讓一個協調流程產生Pub/Sub 訊息,傳送至另一個協調系統。

一般提示

決定使用 Workflows 做為服務協調器後,請記住下列實用提示。

避免以硬式編碼方式寫入網址

您可以避免使用硬式編碼的網址,支援可在多個環境中移植的工作流程,並簡化維護作業。您可以透過下列方式達成此目標:

  • 將網址定義為執行階段引數

    透過用戶端程式庫或 API 叫用工作流程時,這項功能會很有幫助。(不過,如果工作流程是由 Eventarc 的事件觸發,且唯一可傳遞的引數是事件酬載,則無法使用這項功能)。

    範例

    main:
      params: [args]
      steps:
        - init:
            assign:
              - url1: ${args.urls.url1}
              - url2: ${args.urls.url2}

    執行工作流程時,您可以指定網址。舉例來說:

    gcloud workflows run multi-env --data='{"urls":{"url1": "URL_ONE", "url2": "URL_TWO"}}'
  • 使用環境變數,並建立工作流程,根據部署環境動態設定。或者,建立可重複使用的範本工作流程,並根據個別維護的環境變數進行設定。

  • 使用替代技術建立單一工作流程定義檔,但透過工具取代工作流程中的預留位置,部署變體。舉例來說,您可以使用 Cloud Build 部署工作流程,並在 Cloud Build 設定檔中新增步驟,以取代工作流程中的預留位置網址。

    範例

    steps: id: 'replace-urls'
      name: 'gcr.io/cloud-builders/gcloud'
      entrypoint: bash
      args:
        - -c
        - |
          sed -i -e "s~REPLACE_url1~$_URL1~" workflow.yaml
          sed -i -e "s~REPLACE_url2~$_URL2~" workflow.yaml id: 'deploy-workflow'
      name: 'gcr.io/cloud-builders/gcloud'
      args: ['workflows', 'deploy', 'multi-env-$_ENV', '--source', 'workflow.yaml']

    然後,您可以在建構時 替換變數值。例如:

    gcloud builds submit --config cloudbuild.yaml \
        --substitutions=_ENV=staging,_URL1="URL_ONE",_URL2="URL_TWO"

    詳情請參閱「透過 CLI 和 API 提交建構作業」。

    或者,您也可以使用 Terraform 佈建基礎架構,並定義設定檔,透過輸入變數為每個環境建立工作流程。

    範例

    variable "project_id" {
      type = string
    }
    
    variable "url1" {
      type = string
    }
    
    variable "url2" {
      type = string
    }
    
    locals {
      env = ["staging", "prod"]
    }
    
    # Define and deploy staging and production workflows
    resource "google_workflows_workflow" "multi-env-workflows" {
      for_each = toset(local.env)
    
      name            = "multi-env-${each.key}"
      project         = var.project_id
      region          = "us-central1"
      source_contents = templatefile("${path.module}/workflow.yaml", { url1 : "${var.url1}-${each.key}", url2 : "${var.url2}-${each.key}" })
    }

    在設定的根模組中宣告變數時,可以透過多種方式指派值。例如

    terraform apply -var="project_id=PROJECT_ID" -var="url1=URL_ONE" -var="url2=URL_TWO"
  • 使用 Secret Manager 連接器,在 Secret Manager 中安全地儲存網址並擷取。

使用巢狀步驟

每個工作流程都必須至少有一個步驟。 根據預設,工作流程會將步驟視為有序清單,並逐一執行,直到所有步驟都執行完畢為止。從邏輯上來看,部分步驟應歸為一組,您可以使用 steps 區塊,將一系列步驟巢狀化。這樣很方便,因為您可以指向要處理一組步驟的正確原子步驟。

範例

main:
    params: [input]
    steps:
    - callWikipedia:
        steps:
        - checkSearchTermInInput:
            switch:
                - condition: ${"searchTerm" in input}
                  assign:
                    - searchTerm: ${input.searchTerm}
                  next: readWikipedia
        - getCurrentDate:
            call: http.get
            args:
                url: https://timeapi.io/api/Time/current/zone?timeZone=Europe/Amsterdam
            result: currentDate
        - setFromCallResult:
            assign:
                - searchTerm: ${currentDate.body.dayOfWeek}
        - readWikipedia:
            call: http.get
            args:
                url: https://en.wikipedia.org/w/api.php
                query:
                    action: opensearch
                    search: ${searchTerm}
            result: wikiResult
    - returnOutput:
            return: ${wikiResult.body[1]}

包裝運算式

所有運算式都必須以 $ 開頭,並以大括號括住:

${EXPRESSION}

如要避免 YAML 剖析問題,請將運算式加上引號。舉例來說,如果系統將含有半形冒號的運算式解讀為定義對應,可能會導致非預期的行為。如要解決這個問題,請將 YAML 運算式放在單引號中:

'${"Name: " + myVar}'

您也可以使用跨越多行的運算式。舉例來說,使用 Workflows BigQuery 連接器時,您可能需要將 SQL 查詢加上引號。

範例

- runQuery:
    call: googleapis.bigquery.v2.jobs.query
    args:
        projectId: ${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")}
        body:
            useLegacySql: false
            useQueryCache: false
            timeoutMs: 30000
            # Find top 100 titles with most views on Wikipedia
            query: ${
                "SELECT TITLE, SUM(views)
                FROM `bigquery-samples.wikipedia_pageviews." + table + "`
                WHERE LENGTH(TITLE) > 10
                GROUP BY TITLE
                ORDER BY SUM(VIEWS) DESC
                LIMIT 100"
                }
    result: queryResult

如需完整的工作流程定義,請參閱「平行執行多個 BigQuery 工作」。

使用宣告式呼叫

您可以使用 Workflows 從工作流程本身呼叫服務並處理結果,以及執行簡單工作,例如發出 HTTP 呼叫。工作流程可以叫用服務、剖析回應,以及為其他連結服務建構輸入內容。呼叫服務可避免額外呼叫、其他依附元件,以及服務呼叫服務等複雜情況。考慮以宣告式 API 呼叫取代不含業務邏輯的服務,並使用 Workflows 簡化複雜度。

不過,如果工作太過複雜,不適合使用 Workflows,您就應該建立服務來完成。舉例來說,如果需要實作可重複使用的業務邏輯、複雜的運算,或是 Workflows 運算式和標準程式庫不支援的轉換,就應該建立服務。複雜案例通常較容易以程式碼實作,而非使用 YAML 或 JSON 和工作流程語法

只儲存必要資料

請控管記憶體用量,以免遇到資源限制,或出現 ResourceLimitErrorMemoryLimitExceededErrorResultSizeLimitExceededError 等指出此問題的錯誤。

請謹慎選擇要儲存在變數中的內容,只篩選並儲存您需要的內容。如果服務傳回的酬載過大,請使用獨立函式為您發出呼叫,並只傳回必要內容。

您可以清除變數來釋放記憶體。舉例來說,您可能想釋出後續步驟所需的記憶體。或者,您可能不希望系統顯示某些通話的結果,因此可以完全省略這些結果。

如要清除變數,請指派 null。在 YAML 中,您也可以將空值或 ~ 指派給變數。這會找出可安全回收的記憶體。

範例

  - step:
      assign:
        - bigVar:

使用子工作流程和外部工作流程

您可以使用子工作流程定義要多次呼叫的邏輯片段或一組步驟,簡化工作流程定義。子工作流程類似於程式設計語言中的函式或常式。這些函式可以接受參數並傳回值,讓您建立更複雜的工作流程,並擴大應用範圍。

請注意,子工作流程是工作流程定義的本機項目,無法在其他工作流程中重複使用。不過,您可以從其他工作流程呼叫工作流程。您可以使用 Workflows 連接器完成這項作業。詳情請參閱 Workflow Executions APIWorkflows API 的連接器總覽。

使用 Workflows 連接器

Workflows 提供多種連接器,方便您在工作流程中存取其他 Google Cloud 產品。連接器會處理要求的格式化作業,並提供方法和引數,因此您不必瞭解Google Cloud API 的詳細資料,即可簡化服務呼叫作業。此外,連接器也內建處理重試長時間執行的作業的行為,因此您不必重複執行及等待呼叫完成,連接器會為您處理這些作業。

如要呼叫 Google Cloud API,請先確認是否有適用的 Workflows 連接器。如果找不到 Google Cloud 產品的連結器,可以提出要求

瞭解如何使用連接器,如需可用連接器的詳細參考資料,請參閱連接器參考資料

平行執行工作流程步驟

Workflows 可以依序執行步驟,也可以並行執行獨立步驟。在某些情況下,這可以大幅加快工作流程執行速度。詳情請參閱「平行執行工作流程步驟」。

套用重試和 Saga 模式

設計彈性工作流程,可處理暫時和永久的服務故障。舉例來說,如果 HTTP 要求、函式或連接器失敗,或是您自己的工作流程程式碼產生錯誤,工作流程可能會引發錯誤。新增錯誤處理和重試機制,避免某個步驟失敗導致整個工作流程失敗。

部分業務交易會跨越多項服務,因此您需要實作跨服務交易的機制。在分散式交易情境中,傳奇設計模式可管理微服務之間的資料一致性。Saga 是一連串的交易,會為每筆交易發布事件,並觸發下一筆交易。如果交易失敗,Saga 會執行補償交易,抵銷序列中先前的失敗。請試用 GitHub 上的工作流程重試和 Saga 模式教學課程

使用回呼等待

回呼可讓工作流程執行作業等待其他服務向回呼端點提出要求;該要求會繼續執行工作流程。

透過回呼,您可以向工作流程發出信號,指出已發生指定事件,並等待該事件,而不必進行輪詢。舉例來說,你可以建立工作流程,在產品補貨或商品出貨時收到通知;或是等待人工介入,例如審查訂單或驗證翻譯。您也可以使用回呼和 Eventarc 觸發條件等待事件

自動化調度管理長時間執行的工作

如需執行長時間的批次處理工作負載,可以使用 BatchCloud Run 工作,並使用 Workflows 管理服務。這樣一來,您就能結合兩者的優點,有效率地佈建及協調整個程序。

Batch 是一項全代管服務,可讓您在 Compute Engine 虛擬機器 (VM) 執行個體中排定時間、排入佇列和執行批次工作負載。您可以使用 Batch 適用的 Workflows 連接器,排定及執行 Batch 工作。詳情請參閱教學課程

Cloud Run 工作用於執行執行工作 (工作) 的程式碼,並在工作完成時終止。您可以在工作流程中執行 Cloud Run 工作,以便進行更複雜的資料處理作業,或以系統化的方式自動調度管理現有工作。請試試本教學課程,瞭解如何使用 Workflows 執行 Cloud Run 工作。

將長時間執行的工作容器化

您可以使用 Workflows 和 Compute Engine,自動執行長時間執行的容器。舉例來說,您可以將長時間執行的工作容器化,以便在任何位置執行,然後在 Compute Engine VM 上執行容器,最長可達工作流程執行時間 (一年)。

您可以使用 Workflows 自動建立 VM、在 VM 上執行容器,以及刪除 VM。這樣一來,您就能使用伺服器並執行容器,但不必管理兩者,因此可避免複雜性,如果您在使用 Cloud Run 函式或 Cloud Run 等服務時遇到時間限制,這項功能就很有幫助。請試試 GitHub 上的使用 Workflows 和 Compute Engine 執行長時間執行的容器教學課程。

從 Workflows 執行指令列工具

Cloud Build 是一項服務,可在 Google Cloud 上執行建構作業,方法是執行一系列建構步驟,而每個建構步驟都會在 Docker 容器中執行。執行建構步驟類似於執行指令碼中的指令。

Google Cloud CLI 包含 gcloudbqkubectl 指令列工具,但無法直接從 Workflows 執行 gcloud CLI 指令。不過,Cloud Build 提供包含 gcloud CLI 的容器映像檔。您可以在這些容器中執行 gcloud CLI 指令,並使用 Cloud Build 連接器在 Workflows 中建立該步驟。

範例

在工作流程中執行 gcloud

# This example shows how to execute gcloud commands from Workflows
# using Cloud Build and returns the output

main:
  steps:
  - execute_command:
      call: gcloud
      args:
          args: "workflows list"
      result: result
  - return_result:
      return: ${result}

gcloud:
  params: [args]
  steps:
  - create_build:
      call: googleapis.cloudbuild.v1.projects.builds.create
      args:
        projectId: ${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")}
        parent: ${"projects/" + sys.get_env("GOOGLE_CLOUD_PROJECT_ID") + "/locations/global"}
        body:
          serviceAccount: ${sys.get_env("GOOGLE_CLOUD_SERVICE_ACCOUNT_NAME")}
          options:
            logging: CLOUD_LOGGING_ONLY
          steps:
          - name: gcr.io/google.com/cloudsdktool/cloud-sdk
            entrypoint: /bin/bash
            args: ${["-c", "gcloud " + args + " > $$BUILDER_OUTPUT/output"]}
      result: result_builds_create
  - return_build_result:
      return: ${text.split(text.decode(base64.decode(result_builds_create.metadata.build.results.buildStepOutputs[0])), "\n")}

Run kubectl in a workflow:

# This example shows how to execute kubectl commands from Workflows
# using Cloud Build and returns the output

main:
  steps:
  - execute_command:
      call: kubectl
      args:
          args: "--help"
      result: result
  - return_result:
      return: ${result}

kubectl:
  params: [args]
  steps:
  - create_build:
      call: googleapis.cloudbuild.v1.projects.builds.create
      args:
        projectId: ${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")}
        parent: ${"projects/" + sys.get_env("GOOGLE_CLOUD_PROJECT_ID") + "/locations/global"}
        body:
          serviceAccount: ${sys.get_env("GOOGLE_CLOUD_SERVICE_ACCOUNT_NAME")}
          options:
            logging: CLOUD_LOGGING_ONLY
          steps:
          - name: gcr.io/cloud-builders/kubectl
            entrypoint: /bin/bash
            args: ${["-c", "kubectl " + args + " > $$BUILDER_OUTPUT/output"]}
      result: result_builds_create
  - return_build_result:
      return: ${text.split(text.decode(base64.decode(result_builds_create.metadata.build.results.buildStepOutputs[0])), "\n")}

使用 Terraform 建立工作流程

Terraform 是一種基礎架構即程式碼工具,可讓您透過程式碼,以可預測的方式建立、變更及改善雲端基礎架構。

您可以使用 Terraform google_workflows_workflow 資源定義及部署工作流程。詳情請參閱「使用 Terraform 建立工作流程」。

為協助您管理及維護大型工作流程,您可以在個別的 YAML 檔案中建立工作流程,並使用 templatefile 函式將該檔案匯入 Terraform,這個函式會讀取指定路徑的檔案,並將其內容算繪為範本。

範例

  # Define a workflow
  resource "google_workflows_workflow" "workflows_example" {
    name            = "sample-workflow"
    region          = var.region
    description     = "A sample workflow"
    service_account = google_service_account.workflows_service_account.id
    # Import main workflow YAML file
    source_contents = templatefile("${path.module}/workflow.yaml",{})
  }

同樣地,如果主要工作流程會呼叫多個子工作流程,您可以在不同檔案中定義主要工作流程和子工作流程,並使用 templatefile 函式匯入這些檔案。

範例

  # Define a workflow
  resource "google_workflows_workflow" "workflows_example" {
    name            = "sample-workflow"
    region          = var.region
    description     = "A sample workflow"
    service_account = google_service_account.workflows_service_account.id
    # Import main workflow and subworkflow YAML files
    source_contents = join("", [
      templatefile(
        "${path.module}/workflow.yaml",{}
      ),

      templatefile(
        "${path.module}/subworkflow.yaml",{}
      )])
  }

請注意,在偵錯工作流程時,如果您參照行號,透過 Terraform 設定檔匯入的所有 YAML 檔案都會合併,並部署為單一工作流程。

從 Git 存放區部署工作流程

Cloud Build 會使用建構觸發條件啟用 CI/CD 自動化功能。您可以設定觸發條件來監聽傳入的事件,例如將新提交內容推送至存放區,或啟動提取要求,然後在收到新事件時自動執行建構作業。

您可以使用 Cloud Build 觸發條件,從 Git 存放區自動啟動建構作業並部署工作流程。您可以設定讓觸發條件在原始碼存放區發生任何變更時部署工作流程,或只有在變更符合特定條件時部署工作流程。

這個方法有助於管理部署生命週期。舉例來說,您可以將變更部署至測試環境中的工作流程,針對該環境執行測試,然後逐步將這些變更發布至正式版環境。詳情請參閱使用 Cloud Build 從 Git 存放區部署工作流程

最佳化用量

執行工作流程的成本極低。不過,如果用量很高,請套用下列規範,盡量減少用量並降低費用:

  • 請確保對 Google Cloud服務的所有呼叫都使用 *.appspot.com*.cloud.goog*.cloudfunctions.net*.run.app,這樣系統就會針對內部步驟而非外部步驟向您收費。

  • 套用自訂重試政策,在延遲時間和可靠性需求與費用之間取得平衡。重試次數越頻繁,延遲時間就越短,可靠性也會提高,但費用可能會增加。

  • 使用等待長時間執行的作業的連接器時,請設定自訂輪詢政策,以最佳化延遲時間來降低成本。舉例來說,如果您預期作業會耗費超過一小時,您可能會希望政策先在一分鐘後輪詢 (以防立即發生失敗),然後每 15 分鐘輪詢一次。

  • 指派作業合併成一個步驟。

  • 避免過度使用 sys.log 步驟。建議改用通話記錄

最佳做法摘要

下表摘要說明本文建議的一般提示和最佳做法。

一般提示
最佳做法

後續步驟