Mengurutkan pesan

Pengurutan pesan adalah fitur di Pub/Sub yang memungkinkan Anda menerima pesan di klien pelanggan sesuai urutan saat 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 masih dipertahankan.

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

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-hal berikut:

  • Kunci pengurutan: 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 region, Anda harus memublikasikan semua pesan dengan kunci pengurutan yang sama di region yang sama. Beberapa contoh kunci urutan adalah ID pelanggan dan kunci utama baris dalam database.

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

    Kunci pengurutan tidak setara 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 dalam urutan saat pesan diterima oleh layanan. Anda harus mengaktifkan setelan ini di langganan.

    Anggaplah Anda memiliki dua langganan A dan B yang terpasang ke topik T yang sama. Langganan A dikonfigurasi dengan pengurutan pesan diaktifkan dan langganan B dikonfigurasi tanpa pengurutan pesan 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 publikasinya. Sedangkan, langganan B menerima pesan tanpa urutan 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 terurut

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

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

  • Pengurutan di seluruh kunci: Pesan yang dipublikasikan dengan kunci pengurutan yang berbeda tidak akan diterima secara berurutan. Misalkan 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 datang sebelum atau sesudah pesan 4.

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

  • Penundaan konfirmasi dan topik dead-letter: 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 menjaga ketertiban di seluruh peristiwa tersebut, pastikan semua pesan dikonfirmasi tepat waktu. Jika konfirmasi tepat waktu tidak memungkinkan, pertimbangkan untuk menggunakan topik dead-letter untuk mencegah penangguhan pesan tanpa batas waktu. Perhatikan bahwa urutan pesan mungkin tidak dipertahankan saat pesan ditulis ke topik dead-letter.

  • Afinitas pesan (klien streamingPull): Pesan untuk kunci yang sama biasanya dikirim ke klien pelanggan streamingPull yang sama. Minat diharapkan saat pesan belum terkirim untuk kunci pengurutan ke klien pelanggan tertentu. Jika tidak ada pesan yang tertunda, afinitas mungkin berubah untuk load balancing atau koneksi klien terputus.

    Untuk memastikan pemrosesan yang lancar meskipun dengan potensi perubahan afinitas, Anda harus mendesain aplikasi streamingPull 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 mekanismenya 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 diskalakan ke miliaran kunci pengurutan. Jumlah kunci pengurutan yang lebih besar memungkinkan pengiriman paralel yang lebih banyak kepada pelanggan karena pengurutan berlaku untuk semua pesan dengan kunci pengurutan yang sama.

Pengiriman pesanan memiliki beberapa konsekuensi. Dibandingkan dengan pengiriman tanpa urutan, pengiriman dengan urutan mengurangi ketersediaan publikasi dan meningkatkan latensi pengiriman pesan menyeluruh. Dalam kasus pengiriman berurutan, failover memerlukan koordinasi untuk memastikan pesan ditulis dan dibaca dalam urutan yang benar.

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

Perilaku klien pelanggan untuk pengurutan pesan

Klien pelanggan menerima pesan sesuai urutan saat pesan tersebut dipublikasikan di wilayah 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 jenis langganan ini lebih lanjut, 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 subscriber harus memastikan bahwa pekerjaan asinkron dilakukan secara berurutan. Salah satu opsi adalah menambahkan pesan ke antrean tugas lokal yang diproses secara berurutan.

Menarik klien pelanggan

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 tepat dalam daftar.

  • Hanya satu batch pesan yang dapat tertunda untuk kunci pengurutan dalam 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 dikirimnya untuk permintaan pull pelanggan.

Klien pelanggan push

Batasan pada push bahkan lebih ketat daripada pada pull. Untuk langganan push, Pub/Sub hanya mendukung satu pesan yang belum terkirim untuk setiap kunci pengurutan dalam satu waktu. Setiap pesan dikirim ke endpoint push sebagai permintaan terpisah. Dengan demikian, mengirim permintaan secara paralel akan memiliki masalah yang sama seperti mengirimkan beberapa batch pesan untuk kunci pengurutan yang sama untuk menarik subscriber 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.

Mengekspor klien pelanggan

Ekspor langganan mendukung pesan yang diurutkan. Untuk langganan BigQuery, pesan dengan kunci pengurutan yang sama akan 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 diurutkan. Jika tersebar di beberapa file, pesan berikutnya untuk kunci pengurutan dapat muncul dalam file dengan nama yang memiliki stempel waktu lebih awal daripada stempel waktu dalam nama file dengan pesan sebelumnya.

Mengaktifkan pengurutan pesan

Untuk menerima pesan secara berurutan, tetapkan properti pengurutan pesan di langganan tempat Anda menerima pesan. 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 konsol Google Cloud, buka halaman Langganan.

Buka Langganan

  1. Klik Buat langganan.

  2. Masukkan ID Langganan.

  3. Pilih topik yang ingin Anda terima pesannya.

  4. Di bagian Pengurutan pesan, pilih Urutkan pesan dengan kunci pengurutan.

  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: project ID 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

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"
	"time"

	"cloud.google.com/go/pubsub"
)

func createWithOrdering(w io.Writer, projectID, subID string, topic *pubsub.Topic) error {
	// projectID := "my-project-id"
	// subID := "my-sub"
	// topic of type https://godoc.org/cloud.google.com/go/pubsub#Topic
	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.CreateSubscription(ctx, subID, pubsub.SubscriptionConfig{
		Topic:                 topic,
		AckDeadline:           20 * time.Second,
		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 Java API Pub/Sub.

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 API Node.js Pub/Sub.

/**
 * 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 API Node.js Pub/Sub.

/**
 * 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

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

topic        = pubsub.topic topic_id
subscription = topic.subscribe subscription_id,
                               message_ordering: true

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

Langkah selanjutnya