Mengurutkan pesan

Pengurutan pesan adalah fitur di Pub/Sub yang memungkinkan Anda menerima pesan di klien pelanggan sesuai urutan pesan tersebut dipublikasikan oleh klien penayang.

Misalnya, asumsikan bahwa klien penayang di suatu region memublikasikan pesan 1, 2, dan 3 secara berurutan. Dengan pengurutan pesan, klien pelanggan akan menerima pesan yang dipublikasikan dalam urutan yang sama. Agar dapat dikirim secara berurutan, klien penayang harus memublikasikan pesan di region yang sama. Namun, pelanggan dapat terhubung ke region mana pun dan jaminan pengurutan tetap dipertahankan.

Pengurutan pesan adalah fitur yang berguna untuk skenario seperti pengambilan perubahan database, pelacakan sesi pengguna, dan aplikasi streaming yang mengutamakan kronologi peristiwa.

Halaman ini menjelaskan konsep pengurutan pesan dan cara menyiapkan klien pelanggan untuk menerima pesan secara berurutan. Untuk mengonfigurasi klien penayang untuk pengurutan pesan, lihat Menggunakan kunci pengurutan untuk memublikasikan pesan.

Ringkasan pengurutan pesan

Pengurutan di Pub/Sub ditentukan oleh hal berikut:

  • Kunci pengurutan: Kunci ini adalah string yang digunakan dalam metadata pesan Pub/Sub dan mewakili entity yang pesannya harus diurutkan. Panjang kunci pengurutan dapat mencapai 1 KB. Untuk menerima kumpulan pesan yang diurutkan di suatu region, Anda harus memublikasikan semua pesan dengan kunci pengurutan yang sama di region yang sama. Beberapa contoh kunci pengurutan adalah ID pelanggan dan kunci utama baris dalam database.

    Throughput publikasi pada setiap kunci pengurutan dibatasi hingga 1 MBps. Throughput di semua kunci pengurutan pada topik dibatasi hingga kuota yang tersedia di region publikasi. Batas ini dapat ditingkatkan hingga beberapa unit GBps.

    Kunci pengurutan tidak sama dengan partisi dalam sistem pesan berbasis partisi karena kunci pengurutan diharapkan memiliki kardinalitas yang jauh lebih tinggi daripada partisi.

  • Aktifkan pengurutan pesan: Ini adalah setelan langganan. Jika langganan mengaktifkan pengurutan pesan, klien pelanggan akan menerima pesan yang dipublikasikan di region yang sama dengan kunci pengurutan yang sama sesuai urutan pesan tersebut diterima oleh layanan. Anda harus mengaktifkan setelan ini di langganan.

    Asumsikan Anda memiliki dua langganan A dan B yang terlampir ke topik T yang sama. Langganan A dikonfigurasi dengan pengurutan pesan yang diaktifkan dan langganan B dikonfigurasi tanpa pengurutan pesan yang diaktifkan. Dalam arsitektur ini, langganan A dan B menerima kumpulan pesan yang sama dari topik T. Jika Anda memublikasikan pesan dengan kunci pengurutan di region yang sama, langganan A akan menerima pesan sesuai urutan pesan tersebut dipublikasikan. Sedangkan, langganan B menerima pesan tanpa pengurutan yang diharapkan.

Secara umum, jika solusi Anda mengharuskan klien penayang mengirim pesan yang diurutkan dan tidak diurutkan, buat topik terpisah, satu untuk pesan yang diurutkan dan yang lainnya untuk pesan yang tidak diurutkan.

Pertimbangan saat menggunakan pesan yang diurutkan

Daftar berikut berisi informasi penting terkait perilaku pesan yang diurutkan di Pub/Sub:

  • Pengurutan dalam kunci: Pesan yang dipublikasikan dengan kunci pengurutan yang sama diharapkan diterima secara berurutan. Asumsikan bahwa untuk kunci pengurutan A, Anda memublikasikan pesan 1, 2, dan 3. Dengan pengurutan yang diaktifkan, 1 diharapkan dikirim sebelum 2 dan 2 diharapkan dikirim sebelum 3.

  • Pengurutan lintas kunci: Pesan yang dipublikasikan dengan kunci pengurutan yang berbeda tidak diharapkan diterima secara berurutan. Asumsikan Anda memiliki kunci pengurutan A dan B. Untuk kunci pengurutan A, pesan 1 dan 2 dipublikasikan secara berurutan. Untuk kunci pengurutan B, pesan 3 dan 4 dipublikasikan secara berurutan. Namun, pesan 1 dapat tiba sebelum atau setelah pesan 4.

  • Pengiriman ulang pesan: Pub/Sub mengirimkan setiap pesan setidaknya sekali, sehingga layanan Pub/Sub dapat mengirimkan ulang pesan. Pengiriman ulang pesan akan memicu pengiriman ulang semua pesan berikutnya untuk kunci tersebut, bahkan pesan yang dikonfirmasi. Asumsikan bahwa klien pelanggan menerima pesan 1, 2, dan 3 untuk kunci pengurutan tertentu. Jika pesan 2 dikirim ulang (karena batas waktu konfirmasi telah berakhir atau konfirmasi upaya terbaik tidak dipertahankan di Pub/Sub), pesan 3 juga akan dikirim ulang. Jika pengurutan pesan dan topik pesan yang dihentikan pengirimannya diaktifkan pada langganan, perilaku ini mungkin tidak berlaku, karena Pub/Sub meneruskan pesan ke topik pesan yang dihentikan pengirimannya berdasarkan upaya terbaik.

  • Penundaan konfirmasi dan topik pesan yang dihentikan pengirimannya: Pesan yang tidak dikonfirmasi untuk kunci pengurutan tertentu berpotensi menunda pengiriman pesan untuk kunci pengurutan lainnya, terutama selama server dimulai ulang atau perubahan traffic. Untuk mempertahankan urutan di seluruh peristiwa tersebut, pastikan konfirmasi semua pesan dilakukan tepat waktu. Jika konfirmasi tepat waktu tidak memungkinkan, pertimbangkan untuk menggunakan topik pesan yang dihentikan pengirimannya untuk mencegah penahanan pesan tanpa batas waktu. Perlu diketahui bahwa urutan mungkin tidak dipertahankan saat pesan ditulis ke topik pesan yang dihentikan pengirimannya.

  • Afinitas pesan (klien streamingPull): Pesan untuk kunci yang sama biasanya dikirim ke klien pelanggan streamingPull yang sama. Afinitas diharapkan terjadi saat pesan tertunda untuk kunci pengurutan ke klien pelanggan tertentu. Jika tidak ada pesan yang tertunda, afinitas dapat bergeser untuk load balancing atau pemutusan koneksi klien.

    Untuk memastikan pemrosesan yang lancar meskipun ada potensi perubahan afinitas, penting untuk mendesain aplikasi streamingPull Anda sedemikian rupa sehingga dapat menangani pesan di klien mana pun untuk kunci pengurutan tertentu.

  • Integrasi dengan Dataflow: Jangan aktifkan pengurutan pesan untuk langganan saat mengonfigurasi Dataflow dengan Pub/Sub. Dataflow memiliki mekanisme sendiri untuk pengurutan pesan total, yang memastikan urutan kronologis di semua pesan sebagai bagian dari operasi jendela. Metode pengurutan ini berbeda dengan pendekatan berbasis kunci pengurutan Pub/Sub. Menggunakan kunci pengurutan dengan Dataflow berpotensi mengurangi performa pipeline.

  • Penskalaan otomatis: Pengiriman yang diurutkan Pub/Sub dapat diskalakan hingga miliaran kunci pengurutan. Jumlah kunci pengurutan yang lebih besar memungkinkan pengiriman yang lebih paralel ke pelanggan karena pengurutan berlaku untuk semua pesan dengan kunci pengurutan yang sama.

  • Kompromi performa: Pengiriman yang diurutkan memiliki beberapa kompromi. Dibandingkan dengan pengiriman yang tidak diurutkan, pengiriman yang diurutkan akan mengurangi ketersediaan publikasi dan meningkatkan latensi pengiriman pesan end-to-end. Dalam kasus pengiriman yang diurutkan, failover memerlukan koordinasi untuk memastikan pesan ditulis dan dibaca dalam urutan yang benar.

  • Kunci populer: Saat menggunakan pengurutan pesan, semua pesan dengan kunci pengurutan yang sama akan dikirim ke klien pelanggan sesuai urutan pesan tersebut diterima oleh layanan. Callback pengguna tidak berjalan hingga callback selesai untuk pesan sebelumnya. Throughput maksimum untuk pesan yang menggunakan kunci pengurutan yang sama saat dikirim ke pelanggan tidak dibatasi oleh Pub/Sub , tetapi oleh kecepatan pemrosesan klien pelanggan Anda. Kunci populer terjadi saat backlog dibuat pada kunci pengurutan individual karena jumlah pesan yang dihasilkan per detik melebihi jumlah pesan yang dapat diproses pelanggan per detik. Untuk mengurangi kunci populer, gunakan kunci yang paling terperinci dan minimalkan waktu pemrosesan per pesan. Anda juga dapat memantau metrik subscription/oldest_unacked_message_age untuk nilai yang meningkat, yang mungkin menunjukkan kunci populer.

Untuk mengetahui informasi selengkapnya tentang cara menggunakan pengurutan pesan, lihat topik praktik terbaik berikut:

Perilaku klien pelanggan untuk pengurutan pesan

Klien pelanggan menerima pesan sesuai urutan pesan tersebut dipublikasikan di region tertentu. Pub/Sub mendukung berbagai cara untuk menerima pesan, seperti klien pelanggan yang terhubung ke langganan pull dan push. Library klien menggunakan streamingPull (kecuali PHP).

Untuk mempelajari lebih lanjut jenis langganan ini, lihat Memilih jenis langganan.

Bagian berikut membahas arti menerima pesan secara berurutan untuk setiap jenis klien pelanggan.

Klien pelanggan streamingPull

Saat menggunakan library klien dengan streamingPull, Anda harus menentukan callback pengguna yang berjalan setiap kali pesan diterima oleh klien pelanggan. Dengan library klien, untuk kunci pengurutan tertentu, callback dijalankan hingga selesai pada pesan dalam urutan yang benar. Jika pesan dikonfirmasi dalam callback tersebut, semua komputasi pada pesan akan terjadi secara berurutan. Namun, jika callback pengguna menjadwalkan pekerjaan asinkron lainnya pada pesan, klien pelanggan harus memastikan bahwa pekerjaan asinkron dilakukan secara berurutan. Salah satu opsinya adalah menambahkan pesan ke antrean kerja lokal yang diproses secara berurutan.

Klien pelanggan pull

Untuk klien pelanggan yang terhubung ke langganan pull, pengurutan pesan Pub/Sub mendukung hal berikut:

  • Semua pesan untuk kunci pengurutan di PullResponse berada dalam urutan yang benar dalam daftar.

  • Hanya satu batch pesan yang dapat tertunda untuk kunci pengurutan pada satu waktu.

Persyaratan bahwa hanya satu batch pesan yang dapat tertunda pada satu waktu diperlukan untuk mempertahankan pengiriman yang diurutkan karena layanan Pub/Sub tidak dapat memastikan keberhasilan atau latensi respons yang dikirim untuk permintaan pull pelanggan.

Klien pelanggan push

Pembatasan pada push bahkan lebih ketat daripada pembatasan pada pull. Untuk langganan push, Pub/Sub hanya mendukung satu pesan yang tertunda untuk setiap kunci pengurutan pada satu waktu. Setiap pesan dikirim ke endpoint push sebagai permintaan terpisah. Oleh karena itu, mengirim permintaan secara paralel akan memiliki masalah yang sama dengan mengirim beberapa batch pesan untuk kunci pengurutan yang sama ke pelanggan pull secara bersamaan. Langganan push mungkin bukan pilihan yang baik untuk topik yang pesannya sering dipublikasikan dengan kunci pengurutan yang sama atau jika latensi sangat penting.

Klien pelanggan ekspor

Langganan ekspor mendukung pesan yang diurutkan. Untuk langganan BigQuery, pesan dengan kunci pengurutan yang sama ditulis ke tabel BigQuery secara berurutan. Untuk langganan Cloud Storage, pesan dengan kunci pengurutan yang sama mungkin tidak semuanya ditulis ke file yang sama. Jika berada dalam file yang sama, pesan untuk kunci pengurutan akan berurutan. Jika tersebar di beberapa file, pesan yang lebih baru untuk kunci pengurutan dapat muncul dalam file dengan nama yang memiliki stempel waktu yang lebih awal daripada stempel waktu dalam nama file dengan pesan yang lebih awal.

Mengaktifkan pengurutan pesan

Untuk menerima pesan secara berurutan, tetapkan properti pengurutan pesan pada langganan yang Anda terima pesannya. Menerima pesan secara berurutan dapat meningkatkan latensi. Anda tidak dapat mengubah properti pengurutan pesan setelah membuat langganan.

Anda dapat menetapkan properti pengurutan pesan saat membuat langganan menggunakan konsol Google Cloud , Google Cloud CLI, atau Pub/Sub API.

Konsol

Untuk membuat langganan dengan properti pengurutan pesan, ikuti langkah-langkah berikut:

  1. Di Google Cloud konsol, buka halaman Subscriptions.

Buka Langganan

  1. Klik Create subscription.

  2. Masukkan Subscription ID.

  3. Pilih topik yang pesannya ingin Anda terima.

  4. Di bagian Message ordering, pilih Order messages with an ordering key.

  5. Klik Create.

gcloud

Untuk membuat langganan dengan properti pengurutan pesan, gunakan perintah gcloud pubsub subscriptions create dan flag --enable-message-ordering:

gcloud pubsub subscriptions create SUBSCRIPTION_ID \
  --enable-message-ordering

Ganti SUBSCRIPTION_ID dengan ID langganan.

Jika permintaan berhasil, command line akan menampilkan konfirmasi:

Created subscription [SUBSCRIPTION_ID].

REST

Untuk membuat langganan dengan properti pengurutan pesan, kirim permintaan PUT seperti berikut:

PUT https://pubsub.googleapis.com/v1/projects/PROJECT_ID/subscriptions/SUBSCRIPTION_ID
Authorization: Bearer $(gcloud auth application-default print-access-token)

Ganti kode berikut:

  • PROJECT_ID: ID project project dengan topik
  • SUBSCRIPTION_ID: ID langganan

Dalam isi permintaan, tentukan hal berikut:

{
  "topic": TOPIC_ID,
  "enableMessageOrdering": true,
}

Ganti TOPIC_ID dengan ID topik yang akan dilampirkan ke langganan.

Jika permintaan berhasil, responsnya adalah langganan dalam format JSON:

{
  "name": projects/PROJECT_ID/subscriptions/SUBSCRIPTION_ID,
  "topic": projects/PROJECT_ID/topics/TOPIC_ID,
  "enableMessageOrdering": true,
}

C++

Sebelum mencoba contoh ini, ikuti petunjuk penyiapan C++ di Panduan memulai: Menggunakan Library Klien. Untuk mengetahui informasi selengkapnya, lihat dokumentasi referensi Pub/Sub C++ API.

namespace pubsub = ::google::cloud::pubsub;
namespace pubsub_admin = ::google::cloud::pubsub_admin;
[](pubsub_admin::SubscriptionAdminClient client,
   std::string const& project_id, std::string const& topic_id,
   std::string const& subscription_id) {
  google::pubsub::v1::Subscription request;
  request.set_name(
      pubsub::Subscription(project_id, subscription_id).FullName());
  request.set_topic(pubsub::Topic(project_id, topic_id).FullName());
  request.set_enable_message_ordering(true);
  auto sub = client.CreateSubscription(request);
  if (sub.status().code() == google::cloud::StatusCode::kAlreadyExists) {
    std::cout << "The subscription already exists\n";
    return;
  }
  if (!sub) throw std::move(sub).status();

  std::cout << "The subscription was successfully created: "
            << sub->DebugString() << "\n";
}

C#

Sebelum mencoba contoh ini, ikuti petunjuk penyiapan C# di Panduan memulai: Menggunakan Library Klien. Untuk mengetahui informasi selengkapnya, lihat dokumentasi referensi Pub/Sub C# API.


using Google.Cloud.PubSub.V1;
using Grpc.Core;

public class CreateSubscriptionWithOrderingSample
{
    public Subscription CreateSubscriptionWithOrdering(string projectId, string topicId, string subscriptionId)
    {
        SubscriberServiceApiClient subscriber = SubscriberServiceApiClient.Create();
        var topicName = TopicName.FromProjectTopic(projectId, topicId);
        var subscriptionName = SubscriptionName.FromProjectSubscription(projectId, subscriptionId);

        var subscriptionRequest = new Subscription
        {
            SubscriptionName = subscriptionName,
            TopicAsTopicName = topicName,
            EnableMessageOrdering = true
        };

        Subscription subscription = null;
        try
        {
            subscription = subscriber.CreateSubscription(subscriptionRequest);
        }
        catch (RpcException e) when (e.Status.StatusCode == StatusCode.AlreadyExists)
        {
            // Already exists.  That's fine.
        }
        return subscription;
    }
}

Go

Contoh berikut menggunakan library klien Go Pub/Sub versi utama (v2). Jika Anda masih menggunakan library v1, lihat panduan migrasi ke v2. Untuk melihat daftar contoh kode v1, lihat contoh kode yang tidak digunakan lagi.

Sebelum mencoba contoh ini, ikuti petunjuk penyiapan Go di Panduan memulai: Menggunakan Library Klien. Untuk mengetahui informasi selengkapnya, lihat dokumentasi referensi Pub/Sub Go API.

import (
	"context"
	"fmt"
	"io"

	"cloud.google.com/go/pubsub/v2"
	"cloud.google.com/go/pubsub/v2/apiv1/pubsubpb"
)

func createWithOrdering(w io.Writer, projectID, topic, subscription string) error {
	// projectID := "my-project-id"
	// topic := "projects/my-project-id/topics/my-topic"
	// subscription := "projects/my-project/subscriptions/my-sub"
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("pubsub.NewClient: %w", err)
	}
	defer client.Close()

	// Message ordering can only be set when creating a subscription.
	sub, err := client.SubscriptionAdminClient.CreateSubscription(ctx, &pubsubpb.Subscription{
		Name:                  subscription,
		Topic:                 topic,
		EnableMessageOrdering: true,
	})
	if err != nil {
		return fmt.Errorf("CreateSubscription: %w", err)
	}
	fmt.Fprintf(w, "Created subscription: %v\n", sub)
	return nil
}

Java

Sebelum mencoba contoh ini, ikuti petunjuk penyiapan Java di Panduan memulai: Menggunakan Library Klien. Untuk mengetahui informasi selengkapnya, lihat dokumentasi referensi Pub/Sub Java API.

import com.google.cloud.pubsub.v1.SubscriptionAdminClient;
import com.google.pubsub.v1.ProjectSubscriptionName;
import com.google.pubsub.v1.ProjectTopicName;
import com.google.pubsub.v1.Subscription;
import java.io.IOException;

public class CreateSubscriptionWithOrdering {
  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";
    String subscriptionId = "your-subscription-id";

    createSubscriptionWithOrderingExample(projectId, topicId, subscriptionId);
  }

  public static void createSubscriptionWithOrderingExample(
      String projectId, String topicId, String subscriptionId) throws IOException {
    try (SubscriptionAdminClient subscriptionAdminClient = SubscriptionAdminClient.create()) {

      ProjectTopicName topicName = ProjectTopicName.of(projectId, topicId);
      ProjectSubscriptionName subscriptionName =
          ProjectSubscriptionName.of(projectId, subscriptionId);

      Subscription subscription =
          subscriptionAdminClient.createSubscription(
              Subscription.newBuilder()
                  .setName(subscriptionName.toString())
                  .setTopic(topicName.toString())
                  // Set message ordering to true for ordered messages in the subscription.
                  .setEnableMessageOrdering(true)
                  .build());

      System.out.println("Created a subscription with ordering: " + subscription.getAllFields());
    }
  }
}

Node.js

Sebelum mencoba contoh ini, ikuti petunjuk penyiapan Node.js di Panduan memulai: Menggunakan Library Klien. Untuk mengetahui informasi selengkapnya, lihat dokumentasi referensi Pub/Sub Node.js API.

/**
 * TODO(developer): Uncomment these variables before running the sample.
 */
// const topicNameOrId = 'YOUR_TOPIC_NAME_OR_ID';
// const subscriptionNameOrId = 'YOUR_SUBSCRIPTION_NAME_OR_ID';

// Imports the Google Cloud client library
const {PubSub} = require('@google-cloud/pubsub');

// Creates a client; cache this for further use
const pubSubClient = new PubSub();

async function createSubscriptionWithOrdering(
  topicNameOrId,
  subscriptionNameOrId,
) {
  // Creates a new subscription
  await pubSubClient
    .topic(topicNameOrId)
    .createSubscription(subscriptionNameOrId, {
      enableMessageOrdering: true,
    });
  console.log(
    `Created subscription ${subscriptionNameOrId} with ordering enabled.`,
  );
  console.log(
    'To process messages in order, remember to add an ordering key to your messages.',
  );
}

Node.js

Sebelum mencoba contoh ini, ikuti petunjuk penyiapan Node.js di Panduan memulai: Menggunakan Library Klien. Untuk mengetahui informasi selengkapnya, lihat dokumentasi referensi Pub/Sub Node.js API.

/**
 * TODO(developer): Uncomment these variables before running the sample.
 */
// const topicNameOrId = 'YOUR_TOPIC_NAME_OR_ID';
// const subscriptionNameOrId = 'YOUR_SUBSCRIPTION_NAME_OR_ID';

// Imports the Google Cloud client library
import {PubSub} from '@google-cloud/pubsub';

// Creates a client; cache this for further use
const pubSubClient = new PubSub();

async function createSubscriptionWithOrdering(
  topicNameOrId: string,
  subscriptionNameOrId: string,
) {
  // Creates a new subscription
  await pubSubClient
    .topic(topicNameOrId)
    .createSubscription(subscriptionNameOrId, {
      enableMessageOrdering: true,
    });
  console.log(
    `Created subscription ${subscriptionNameOrId} with ordering enabled.`,
  );
  console.log(
    'To process messages in order, remember to add an ordering key to your messages.',
  );
}

Python

Sebelum mencoba contoh ini, ikuti petunjuk penyiapan Python di Panduan memulai: Menggunakan Library Klien. Untuk mengetahui informasi selengkapnya, lihat dokumentasi referensi Pub/Sub Python API.

from google.cloud import pubsub_v1

# TODO(developer): Choose an existing topic.
# project_id = "your-project-id"
# topic_id = "your-topic-id"
# subscription_id = "your-subscription-id"

publisher = pubsub_v1.PublisherClient()
subscriber = pubsub_v1.SubscriberClient()
topic_path = publisher.topic_path(project_id, topic_id)
subscription_path = subscriber.subscription_path(project_id, subscription_id)

with subscriber:
    subscription = subscriber.create_subscription(
        request={
            "name": subscription_path,
            "topic": topic_path,
            "enable_message_ordering": True,
        }
    )
    print(f"Created subscription with ordering: {subscription}")

Ruby

Contoh berikut menggunakan library klien Ruby Pub/Sub v3. Jika Anda masih menggunakan library v2, lihat panduan migrasi ke v3. Untuk melihat daftar contoh kode Ruby v2, lihat contoh kode yang tidak digunakan lagi.

Sebelum mencoba contoh ini, ikuti petunjuk penyiapan Ruby di Panduan memulai: Menggunakan Library Klien. Untuk mengetahui informasi selengkapnya, lihat dokumentasi referensi Pub/Sub Ruby API.

# topic_id        = "your-topic-id"
# subscription_id = "your-subscription-id"

pubsub = Google::Cloud::PubSub.new
subscription_admin = pubsub.subscription_admin

subscription = subscription_admin.create_subscription \
  name: pubsub.subscription_path(subscription_id),
  topic: pubsub.topic_path(topic_id),
  enable_message_ordering: true

puts "Pull subscription #{subscription_id} created with message ordering."

Langkah berikutnya