パブリッシュ ヘッジ

メッセージのパブリッシュ時にテール レイテンシが高くなる原因としては、一時的なネットワーク遅延やサーバーサイドの速度低下が考えられます。パブリッシュ ヘッジを使用すると、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 の範囲で指定する必要があります。

パブリッシュ リクエストをヘッジするには、ヘッジ遅延が、パブリッシャーの再試行設定の初期リクエスト タイムアウトと合計タイムアウトの両方よりも短くなければなりません。そうでない場合、パブリッシャー クライアントの初期化は失敗します。パブリッシュ ヘッジが有効になっている場合、クライアント ライブラリは次のようにパブリッシュ リクエストを送信します。

  • 処理中のパブリッシュ リクエストがヘッジ遅延内に完了せず、少なくとも 1 つのトークンが使用可能な場合、クライアント ライブラリは 1 つのトークンを消費し、最初のリクエストを未処理のまま、同じメッセージ バッチに対して追加のパブリッシュ リクエストを並行して送信します。
  • 別のヘッジ遅延の後も処理中のリクエストが完了しない場合、クライアント ライブラリは、トークンが使用可能で、合計タイムアウトが期限切れになっていない限り、ヘッジ遅延の間隔で追加のヘッジ リクエストを送信し続けます。
  • バッチの処理中のパブリッシュ リクエストが成功すると、クライアント ライブラリはパブリッシュ オペレーションを完了し、そのバッチの残りの処理中の試行をキャンセルして、補充率に応じて使用可能なトークンを最大トークン数まで増やします。

パブリッシュ リクエストをヘッジする

再試行リクエストでは、処理中のパブリッシュ リクエストが失敗するかタイムアウトするまで待機しますが、パブリッシュ ヘッジでは、最初のリクエストを未処理のままにして、同時ヘッジ リクエストを送信します。これにより、成功しようとしているリクエストを早期にキャンセルすることなく、テール レイテンシを短縮できます。

同じバッチのメッセージに対する複数のリクエストが同時に処理される可能性があるため、残りの試行がキャンセルされる前に複数の試行が成功する可能性があります。これは、パブリッシュ リクエストのキャンセルがベスト エフォートで行われるためです。その結果、メッセージ 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 の競合やスレッドの枯渇など、クライアントサイドの遅延は解決されません。クライアント メモリ内のメッセージ キューが原因でパブリッシュ レイテンシが高くなっている場合は、フロー制御を使用してキューサイズを管理すると、ホストリソースの制約にも対処できます。
  • パブリッシュのレイテンシとスループットの指標をモニタリングする: topic/send_request_latencies などの Monitoring 指標グラフを使用して、テール レイテンシの急増を特定し、ヘッジが有効かどうかを判断します。CANCELLED エラーの発生率が高い場合は、リクエストの期限が短すぎる可能性があります。効果的にチューニングすると、パブリッシュ ヘッジにより、パブリッシュのテール レイテンシ中であっても、メッセージ スループットとトピックのバイト費用がほぼ一定に保たれます。

次のステップ

詳細なパブリッシュのオプションを構成する方法については、以下をご覧ください。