發布避險

發布訊息時,如果尾端延遲時間過長,可能是因為暫時性網路延遲或伺服器端暫時速度緩慢。如果進行中的要求未在設定的延遲時間內完成,Pub/Sub 發布者用戶端可透過發布避險功能,平行傳送備份 (避險) 發布要求,並使用最先傳回的回應。

本文說明如何對發布至主題的訊息使用發布避險功能。

事前準備

設定發布工作流程前,請務必完成下列工作:

必要的角色

如要取得將避險發布要求傳送至主題所需的權限,請要求管理員授予您主題的 Pub/Sub 發布者 (roles/pubsub.publisher) IAM 角色。如要進一步瞭解如何授予角色,請參閱「管理專案、資料夾和組織的存取權」。

您或許也能透過自訂角色或其他預先定義的角色,取得必要權限。

您需要額外權限,才能建立或更新主題和訂閱項目。

關於發布避險

避險設定可控管 Pub/Sub 用戶端程式庫傳送避險發布要求的時機和方式。發布避險功能預設為停用。啟用後,用戶端程式庫會採用下列避險設定:

  • 避險延遲:如果先前的要求尚未完成,用戶端程式庫在平行傳送額外發布要求前等待的時間。預設值為 1 秒,設定值必須介於 100 毫秒和 10 秒之間。
  • 權杖數量上限:用戶端程式庫可累積的權杖數量上限,用於傳送避險發布要求。每個避險發布要求會耗用 1 個權杖。預設值為 50,設定值必須介於 1 到 250 之間。
  • 補充率:每次成功發布要求時新增的權杖數量。這個值會控制可隨時間避險的發布要求最大比例。舉例來說,如果補充率為 0.1,則最多可對 10% 的發布要求進行避險。預設值為 0.1,設定值必須介於 0.001 至 0.2 之間。

如要對發布要求進行避險,避險延遲時間必須短於發布者重試設定中的初始要求逾時和總逾時時間。否則發布商用戶端將無法初始化。啟用發布避險功能後,用戶端程式庫會按照下列方式傳送發布要求:

  • 如果傳輸中的發布要求未在避險延遲時間內完成,且至少有一個權杖可用,用戶端程式庫就會使用一個權杖,並為同一批訊息平行傳送額外的發布要求,同時保留初始要求。
  • 如果經過另一個避險延遲時間後,仍未完成任何在途要求,用戶端程式庫會繼續以避險延遲時間為間隔,傳送其他避險要求,直到權杖用盡或總逾時時間到期為止。
  • 只要批次中任何處理中的發布要求成功,用戶端程式庫就會完成發布作業、取消該批次中任何剩餘的處理中嘗試,並依據補充比率增加可用權杖,最多可達權杖上限。

對沖發布要求

重試要求會等待進行中的發布要求失敗或逾時,而發布避險則會保留初始要求,同時傳送並行避險要求。這樣可以縮短尾端延遲時間,而不會過早取消即將成功的要求。

由於同一批訊息的多個要求可能同時在傳輸中,因此在取消其餘嘗試之前,可能會有多個嘗試成功,因為發布要求取消是盡力而為。因此,您可能會收到訊息 ID 不同的重複訊息,這可能會增加用戶端網路流量,以及發布和傳送這些重複訊息的 Pub/Sub 費用。如需處理重複訊息的提示,請參閱「排解重複、重新傳送或遺漏訊息的問題」。

如果服務降級導致延遲時間或錯誤持續增加,最大權杖和補充比率設定可防止避險發布率過高。由於只有在發布要求成功時才會新增權杖,因此持續緩慢或錯誤會快速耗盡可用的權杖,並自動限制避險要求。

這段程式碼範例示範如何建立具有自訂避險設定的發布者。並非所有用戶端程式庫都支援發布避險功能,請參閱所選語言的 API 參考文件。

Java

在試用這個範例之前,請先按照「快速入門導覽課程:使用用戶端程式庫」中的 Java 設定操作說明進行操作。詳情請參閱 Pub/Sub Java API 參考文件。


import com.google.api.core.ApiFuture;
import com.google.cloud.pubsub.v1.HedgingSettings;
import com.google.cloud.pubsub.v1.Publisher;
import com.google.protobuf.ByteString;
import com.google.pubsub.v1.PubsubMessage;
import com.google.pubsub.v1.TopicName;
import java.io.IOException;
import java.time.Duration;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

public class PublishWithHedgingSettingsExample {
  public static void main(String... args) throws Exception {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "your-project-id";
    String topicId = "your-topic-id";

    publishWithHedgingSettingsExample(projectId, topicId);
  }

  public static void publishWithHedgingSettingsExample(String projectId, String topicId)
      throws IOException, ExecutionException, InterruptedException {
    TopicName topicName = TopicName.of(projectId, topicId);
    Publisher publisher = null;

    try {
      // Hedging settings configures how and when the publisher sends multiple concurrent publish
      // requests to reduce tail latency.
      Duration hedgeDelay = Duration.ofMillis(500); // default: 1000 ms (1 second)
      int maxTokens = 100; // default: 50
      float refillRatio = 0.05f; // default: 0.1

      HedgingSettings hedgingSettings =
          HedgingSettings.newBuilder()
              .setHedgeDelay(hedgeDelay)
              .setMaxTokens(maxTokens)
              .setRefillRatio(refillRatio)
              .build();

      // Create a publisher instance with hedging settings bound to the topic
      publisher = Publisher.newBuilder(topicName).setHedgingSettings(hedgingSettings).build();

      String message = "Hello world!";
      ByteString data = ByteString.copyFromUtf8(message);
      PubsubMessage pubsubMessage = PubsubMessage.newBuilder().setData(data).build();

      // Once published, returns a server-assigned message id (unique within the topic)
      ApiFuture<String> messageIdFuture = publisher.publish(pubsubMessage);
      String messageId = messageIdFuture.get();
      System.out.println("Published a message with hedging settings: " + messageId);

    } finally {
      if (publisher != null) {
        // When finished with the publisher, shutdown to free up resources.
        publisher.shutdown();
        publisher.awaitTermination(1, TimeUnit.MINUTES);
      }
    }
  }
}

使用排序金鑰發布避險

發布避險功能無法與訊息排序搭配使用。由於發布避險功能會同時傳送同一批訊息的多個發布要求,Pub/Sub 服務可能會不按順序接收及處理這些要求。如果您在發布者用戶端同時啟用訊息排序和發布避險功能,建立發布者時會發生錯誤。

提示與最佳做法

設定發布避險時,請考量下列最佳做法:

  • 使用避險功能處理暫時性尾端延遲:發布避險功能旨在消除因暫時性網路延遲或伺服器端短暫緩慢而造成的短暫延遲高峰。請勿仰賴避險機制來緩解持續中斷或持續錯誤。
  • 使用重試政策進行避險:在重試設定中,設定較長的初始要求逾時時間,以及較短的避險延遲時間。如果逾時時間過短,要求會過早取消並觸發完整重試,導致伺服器上正在進行的工作遭到捨棄。如果原始要求只是稍微延遲,較長的逾時時間可讓原始要求完成。
  • 用戶端流量控制和避險:發布避險無法解決用戶端延遲問題,例如 CPU 爭用或執行緒飢餓。如果發布延遲時間過長,是因為訊息在用戶端記憶體中排隊,使用流量控制管理佇列大小可能有幫助,但主體資源限制也應一併解決。
  • 監控發布延遲時間和處理量指標:使用 Monitoring 指標圖表 (例如 topic/send_request_latencies),找出尾延遲高峰,並判斷避險是否能發揮作用。如果 CANCELLED 錯誤率偏高,可能表示要求期限設得太低。如果調整得當,發布避險功能可讓訊息處理量和主題位元組費用大致保持不變,即使在發布尾端延遲期間也是如此。

後續步驟

如要瞭解如何設定進階發布選項,請參閱下列內容: