Mengurutkan pesan

Pengurutan pesan adalah fitur di Pub/Sub yang memungkinkan Anda menerima pesan di klien pelanggan sesuai urutan yang 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 menerima pesan yang dipublikasikan dalam urutan yang sama. Agar dikirimkan secara berurutan, klien penayang harus memublikasikan pesan di region yang sama.

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

Halaman ini menjelaskan konsep pengurutan pesan dan cara menyiapkan klien pelanggan Anda untuk menerima pesan secara berurutan. Guna 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 pemesanan: Ini adalah string yang digunakan dalam metadata pesan Pub/Sub dan mewakili entity yang pesannya harus dipesan. Panjang kunci pengurutan bisa 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 pemesanan 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 suatu topik dibatasi pada kuota yang tersedia di region publikasi. Batas ini dapat ditingkatkan menjadi banyak 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 penerimaannya oleh layanan. Anda harus mengaktifkan setelan ini dalam langganan.

    Asumsikan Anda memiliki dua langganan A dan B yang melekat pada topik yang sama T. Langganan A dikonfigurasi dengan pengurutan pesan diaktifkan dan langganan B dikonfigurasi tanpa mengaktifkan pengurutan pesan. 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. Sementara itu, langganan B menerima pesan tanpa memerlukan pengurutan apa pun.

Secara umum, jika solusi Anda mengharuskan klien penayang mengirim pesan yang diurutkan dan tidak diurutkan, buat topik terpisah, satu untuk pesan yang diurutkan dan satu lagi 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 mengurutkan kunci A, Anda memublikasikan pesan 1, 2, dan 3. Jika pemesanan diaktifkan, urutan 1 diharapkan akan dikirimkan sebelum nomor 2 dan nomor 2 diharapkan terkirim sebelum tanggal 3.

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

  • Pengiriman ulang pesan: Pub/Sub mengirim setiap pesan minimal satu kali, sehingga layanan Pub/Sub mungkin mengirim 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 dikirimkan ulang. Jika pengurutan pesan dan topik yang dihentikan pengirimannya diaktifkan pada suatu langganan, perilaku ini mungkin tidak benar, karena Pub/Sub meneruskan pesan ke topik yang dihentikan pengirimannya atas dasar upaya terbaik.

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

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

    Untuk memastikan kelancaran pemrosesan meskipun dengan potensi perubahan afinitas, sangat penting untuk mendesain aplikasi streamingPull Anda sedemikian rupa agar 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 total pengurutan pesan, yang memastikan urutan kronologis di semua pesan sebagai bagian dari operasi windowing. Metode pengurutan ini berbeda dengan pendekatan berbasis kunci pemesanan Pub/Sub. Penggunaan kunci pengurutan dengan Dataflow berpotensi mengurangi performa pipeline.

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

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

Untuk mengetahui informasi lebih lanjut tentang cara menggunakan pengurutan pesan, baca 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 setiap kunci pengurutan tertentu, callback akan dijalankan untuk menyelesaikan pesan dengan 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 pilihannya adalah menambahkan pesan ke antrean pekerjaan lokal yang diproses secara berurutan.

Mendapatkan klien pelanggan

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

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

  • Hanya satu batch pesan yang dapat beredar untuk kunci pengurutan dalam satu waktu.

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

Klien pelanggan push

Batasan pada push bahkan lebih ketat daripada yang ada di pull. Untuk langganan push, Pub/Sub hanya mendukung satu pesan yang belum diproses untuk setiap kunci pengurutan dalam satu waktu. Setiap pesan dikirim ke endpoint push sebagai permintaan terpisah. Oleh karena itu, mengirim permintaan secara paralel akan memiliki masalah yang sama seperti pengiriman beberapa batch pesan untuk kunci pengurutan yang sama guna menarik pelanggan secara bersamaan. Langganan push mungkin bukan pilihan yang tepat untuk topik di mana pesan sering dipublikasikan dengan kunci pengurutan yang sama atau ketika latensi sangat penting.

Ekspor klien pelanggan

Ekspor langganan mendukung pesan yang diurutkan. Untuk langganan BigQuery, pesan dengan kunci pengurutan yang sama ditulis ke tabel BigQuery-nya 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. Saat disebarkan di beberapa file, pesan berikutnya untuk kunci pengurutan dapat muncul di file dengan nama yang memiliki stempel waktu lebih awal dari stempel waktu pada nama file dengan pesan sebelumnya.

Mengaktifkan pengurutan pesan

Untuk menerima pesan secara berurutan, tetapkan properti pengurutan pesan di langganan yang pesannya Anda terima. 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 dari mana Anda ingin menerima pesan.

  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 untuk 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 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 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 informasi selengkapnya, lihat dokumentasi referensi API Pub/Sub Java.

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

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