Arsitektur berbasis peristiwa dengan Pub/Sub

Dokumen ini membahas perbedaan antara arsitektur berbasis antrean pesan lokal dan arsitektur berbasis cloud berbasis peristiwa yang diimplementasikan di Pub/Sub. Mencoba menerapkan pola lokal secara langsung ke teknologi berbasis cloud dapat kehilangan nilai unik yang membuat cloud menarik sejak awal.

Dokumen ini ditujukan untuk arsitek sistem yang memigrasikan desain dari arsitektur lokal ke desain berbasis cloud. Dokumen ini mengasumsikan bahwa Anda memiliki pemahaman pengantar tentang sistem pesan.

Diagram berikut menunjukkan ringkasan model antrean pesan dan model Pub/Sub.

Membandingkan arsitektur model antrean pesan dengan model berbasis peristiwa menggunakan Pub/Sub.

Dalam diagram sebelumnya, model antrean pesan dibandingkan dengan model aliran peristiwa Pub/Sub. Dalam model antrean pesan, penayang mengirim pesan ke antrean tempat setiap pelanggan dapat memproses antrean tertentu. Pada model aliran peristiwa yang menggunakan Pub/Sub, penayang mendorong pesan ke topik yang dapat dipantau oleh beberapa pelanggan. Perbedaan di antara model ini dijelaskan di bagian berikut.

Membandingkan streaming peristiwa dan pesan berbasis antrean

Jika menggunakan sistem lokal, Anda sudah memahami bus layanan perusahaan (ESB) dan antrean pesan. Streaming peristiwa adalah pola baru dan terdapat perbedaan penting dengan keunggulan konkret untuk sistem real-time modern.

Dokumen ini membahas perbedaan utama dalam mekanisme transpor dan data payload dalam arsitektur berbasis peristiwa.

Transportasi pesan

Sistem yang memindahkan data dalam model ini disebut broker pesan, dan ada berbagai framework yang diimplementasikan di dalamnya. Salah satu konsep pertama adalah mekanisme dasar yang memindahkan pesan dari penayang ke penerima. Dalam framework pesan lokal, sistem asal memunculkan pesan eksplisit dan jarak jauh yang dipisahkan ke sistem pemrosesan downstream dengan menggunakan antrean pesan sebagai transport.

Diagram berikut menunjukkan model antrean pesan:

Pesan dari penayang akan diteruskan ke antrean unik untuk setiap pelanggan.

Dalam diagram sebelumnya, pesan mengalir dari proses penayang upstream ke proses pelanggan downstream dengan menggunakan antrean pesan.

Sistem A (penayang) mengirim pesan ke antrean pada broker pesan yang ditetapkan untuk Sistem B (pelanggan). Meskipun pelanggan antrean dapat terdiri dari beberapa klien, semua klien tersebut adalah instance duplikat dari Sistem B yang di-deploy untuk penskalaan dan ketersediaan. Jika proses downstream tambahan—misalnya, Sistem C—perlu menggunakan pesan yang sama dari pembuat (Sistem A), maka antrean baru diperlukan. Anda harus mengupdate pembuat untuk memublikasikan pesan ke antrean baru. Model ini sering disebut sebagai penerusan pesan.

Lapisan transportasi pesan untuk antrean ini mungkin memberikan jaminan urutan pesan atau tidak. Sering kali, antrean pesan diharapkan untuk memberikan model jaminan pesanan dengan data yang diurutkan dalam model akses first-in-first-out (FIFO) yang ketat, mirip dengan task queue. Pola ini awalnya mudah diimplementasikan, tetapi pada akhirnya menghadirkan tantangan penskalaan dan operasional. Untuk mengimplementasikan pesan yang diurutkan, sistem membutuhkan proses terpusat untuk mengatur data. Proses ini membatasi kemampuan penskalaan dan mengurangi ketersediaan layanan karena merupakan titik tunggal kegagalan.

Perantara pesan dalam arsitektur ini cenderung menerapkan logika tambahan seperti melacak pelanggan mana yang telah menerima pesan, dan memantau beban pelanggan. Pelanggan cenderung hanya reaktif, tidak memiliki pengetahuan tentang sistem secara keseluruhan, dan hanya menjalankan fungsi setelah pesan diterima. Jenis arsitektur ini disebut smart pipes (sistem antrean pesan) dan endpoint bodoh (pelanggan).

Transportasi Pub/Sub

Serupa dengan sistem berorientasi pesan, sistem streaming peristiwa juga memindahkan pesan dari sistem sumber ke sistem tujuan yang dipisahkan. Namun, alih-alih mengirim setiap pesan ke antrean yang ditargetkan proses, sistem berbasis peristiwa cenderung memublikasikan pesan ke topik bersama, lalu satu atau beberapa penerima berlangganan ke topik tersebut untuk memproses pesan yang relevan pesan.

Diagram berikut menunjukkan cara berbagai pesan dikirim oleh penayang upstream ke satu topik, lalu dirutekan ke pelanggan downstream yang relevan:

Pesan dari penayang didorong ke satu topik untuk semua pelanggan.

Pola publikasi dan berlangganan ini adalah asal istilah pub/sub. Pola ini juga merupakan dasar untuk produk Google Cloud yang disebut Pub/Sub. Dalam dokumen ini, pubsub mengacu pada pola dan Pub/Sub mengacu pada produk.

Pada model pubsub, sistem pesan tidak perlu mengetahui pelanggan mana pun. Layanan ini tidak melacak pesan mana yang telah diterima, dan tidak mengelola beban pada proses yang digunakan. Sebaliknya, pelanggan melacak pesan mana yang telah diterima dan bertanggung jawab untuk mengelola sendiri tingkat beban dan penskalaan.

Salah satu manfaat penting adalah ketika data dalam model pubsub baru digunakan, Anda tidak perlu mengupdate sistem asal untuk memublikasikan ke antrean baru atau data duplikat. Sebagai gantinya, Anda menghubungkan konsumen baru ke langganan baru tanpa memengaruhi sistem yang ada.

Panggilan dalam sistem streaming peristiwa hampir selalu asinkron. Panggilan ini mengirimkan peristiwa dan tidak menunggu respons apa pun. Event asinkron memungkinkan opsi penskalaan yang lebih besar bagi produsen dan konsumen. Namun, pola asinkron ini dapat menimbulkan tantangan jika Anda mengharapkan jaminan urutan pesan FIFO.

Data antrean pesan

Data yang diteruskan antara sistem dalam sistem antrean pesan dan sistem berbasis pubsub umumnya disebut sebagai pesan dalam kedua konteksnya. Namun, model yang menampilkan data tersebut berbeda. Dalam sistem antrean pesan, pesan mencerminkan perintah yang dimaksudkan untuk mengubah status data downstream. Jika Anda melihat data untuk sistem antrean pesan lokal, penayang mungkin menyatakan secara eksplisit tindakan yang harus dilakukan konsumen. Misalnya, pesan inventaris mungkin menunjukkan hal berikut:

<m:SetInventoryLevel>
    <inventoryValue>3001</inventoryValue>
</m: SetInventoryLevel>

Dalam contoh ini, produsen memberi tahu konsumen bahwa mereka perlu menyetel level inventaris ke 3001. Pendekatan ini dapat menjadi tantangan karena produser perlu memahami logika bisnis setiap konsumen dan perlu membuat struktur pesan terpisah untuk berbagai kasus penggunaan. Sistem antrean pesan ini adalah praktik umum dengan monolit besar yang diterapkan oleh sebagian besar perusahaan. Namun, jika Anda ingin bergerak lebih cepat, menskalakan lebih besar, dan berinovasi lebih banyak dari sebelumnya, sistem terpusat ini dapat menjadi hambatan karena perubahan yang berisiko dan lambat.

Ada juga tantangan operasional dengan pola ini. Saat data yang buruk, data duplikat, atau masalah lainnya terjadi dan perlu diperbaiki, model pesan ini akan menimbulkan tantangan yang signifikan. Misalnya, jika perlu me-roll back pesan yang digunakan dalam contoh sebelumnya, Anda tidak tahu nilai yang harus disetel ke nilai yang dikoreksi karena Anda tidak memiliki referensi ke status sebelumnya. Anda tidak memiliki data insight apakah nilai inventaris adalah 3.000 atau 4.000 sebelum pesan tersebut dikirim.

Data Pubsub

Peristiwa adalah cara lain untuk mengirimkan data pesan. Yang unik adalah sistem berbasis peristiwa berfokus pada peristiwa yang terjadi, bukan hasil yang harus terjadi. Data ini berfokus pada detail peristiwa aktual yang dihasilkan, bukan mengirim data yang menunjukkan tindakan yang harus dilakukan konsumen. Anda dapat mengimplementasikan sistem berbasis peristiwa pada berbagai platform, tetapi sistem ini sering terlihat pada sistem berbasis pubsub.

Misalnya, peristiwa inventaris mungkin terlihat seperti berikut:

{ "inventory":-1 }

Data peristiwa sebelumnya menunjukkan bahwa terjadi peristiwa yang menurunkan inventaris sebesar 1. Pesan berfokus pada peristiwa yang terjadi di masa lalu dan bukan status yang akan diubah di masa mendatang. Penayang dapat mengirim pesan secara asinkron, sehingga sistem berbasis peristiwa lebih mudah untuk diskalakan daripada model antrean pesan. Dalam model pubsub, Anda dapat memisahkan logika bisnis sehingga pembuat hanya perlu memahami tindakan yang dilakukan padanya dan tidak perlu memahami proses downstream. Pelanggan data tersebut dapat memilih cara terbaik untuk menangani data yang mereka terima. Karena pesan-pesan ini bukan perintah imperatif, urutan pesan menjadi kurang penting.

Dengan pola ini, akan lebih mudah untuk melakukan roll back perubahan. Dalam contoh ini, tidak ada informasi tambahan yang diperlukan karena Anda dapat menegasikan nilai inventaris untuk memindahkannya ke arah yang berlawanan. Pesan yang datang terlambat atau tidak berurutan tidak lagi menjadi masalah.

Perbandingan model

Dalam skenario ini, Anda memiliki empat item dari produk yang sama dalam inventaris Anda. Satu pelanggan mengembalikan satu jumlah produk, dan pelanggan berikutnya membeli tiga jumlah produk yang sama. Untuk skenario ini, asumsikan bahwa pesan untuk produk yang ditampilkan tertunda.

Tabel berikut membandingkan tingkat inventaris model antrean pesan yang menerima jumlah inventaris dalam urutan yang benar dengan model yang sama yang menerima jumlah inventaris tidak berurutan:

Antrean pesan (urutan yang benar) Antrean pesan (tidak berurutan)
Inventaris awal: 4 Inventaris awal: 4
Pesan 1: setInventory(5) Pesan 2: setInventory(2)
Pesan 2: setInventory(2) Pesan 1: setInventory(5)
Tingkat inventaris: 2 Tingkat inventaris: 5

Pada model antrean pesan, urutan pesan diterima adalah hal penting karena pesan berisi nilai yang telah dihitung sebelumnya. Dalam contoh ini, jika pesan masuk dalam urutan yang benar, tingkat inventarisnya adalah 2. Namun, jika pesan masuk tidak berurutan, tingkat inventarisnya adalah 5, yang berarti tidak akurat.

Tabel berikut membandingkan tingkat inventaris sistem berbasis pubsub yang menerima jumlah inventaris dalam urutan yang benar dengan sistem yang sama yang menerima jumlah inventaris tidak berurutan:

Pubsub (urutan yang benar) Pubsub (tidak berurutan)
Inventaris awal: 4 Inventaris awal: 4
Pesan 2: "inventory":-3 Pesan 1: "inventory":+1
Pesan 1: "inventory":+1 Pesan 2: "inventory":-3
Tingkat inventaris: 2 Tingkat inventaris: 2

Dalam sistem berbasis pubsub, urutan pesan tidak menjadi masalah karena didasarkan pada layanan yang menghasilkan peristiwa. Apa pun urutan pesan yang masuk, tingkat inventarisnya telah akurat.

Diagram berikut menunjukkan bagaimana dalam model antrean pesan, antrean mengeksekusi perintah yang memberi tahu pelanggan bagaimana status harus berubah. Sedangkan dalam model pubsub, pelanggan bereaksi terhadap data peristiwa yang menyatakan apa yang terjadi di penerbit:

Contoh checkout yang membandingkan reaksi terhadap perintah dengan reaksi terhadap peristiwa.

Mengimplementasikan arsitektur berbasis peristiwa

Ada berbagai konsep yang perlu dipertimbangkan saat mengimplementasikan arsitektur berbasis peristiwa. Bagian berikut memperkenalkan beberapa topik tersebut.

Jaminan pengiriman

Salah satu konsep yang muncul dalam diskusi sistem adalah keandalan jaminan pengiriman pesan. Vendor dan sistem yang berbeda mungkin memberikan tingkat keandalan yang berbeda, sehingga penting untuk memahami variasinya.

Jenis jaminan pertama mengajukan pertanyaan sederhana: jika pesan dikirim, apakah pesan tersebut dijamin akan dikirimkan? Inilah yang disebut sebagai pengiriman setidaknya satu kali. Pesan dijamin akan dikirim minimal satu kali, tetapi mungkin dikirim lebih dari sekali.

Jenis jaminan yang berbeda adalah pengiriman paling banyak satu kali. Dengan pengiriman paling banyak satu kali, pesan hanya dikirim maksimum satu kali, tetapi tidak ada jaminan bahwa pesan tersebut benar-benar terkirim.

Variasi terakhir untuk jaminan pengiriman adalah pengiriman tepat satu kali. Pada model ini, sistem mengirim satu dan hanya satu salinan pesan yang dijamin akan dikirimkan.

Urutan dan duplikat

Dalam arsitektur lokal, pesan sering mengikuti model FIFO. Untuk mencapai model ini, sistem pemrosesan terpusat mengelola pengurutan pesan untuk memastikan pengurutan yang akurat. Pesan berurutan menimbulkan tantangan karena untuk setiap pesan yang gagal, semua pesan harus dikirim ulang secara berurutan. Setiap sistem terpusat dapat menjadi tantangan untuk ketersediaan dan skalabilitas. Menskalakan sistem pusat yang mengelola pengurutan biasanya hanya dapat dicapai dengan menambahkan lebih banyak resource ke mesin yang ada. Dengan satu sistem yang mengelola pesanan, masalah keandalan apa pun berdampak pada seluruh sistem, bukan hanya mesin tersebut.

Layanan pesan yang sangat skalabel dan tersedia sering menggunakan beberapa sistem pemrosesan untuk memastikan pesan dikirim setidaknya satu kali. Dengan banyak sistem, pengelolaan urutan pesan tidak dapat dijamin.

Arsitektur berbasis peristiwa tidak mengandalkan urutan pesan dan dapat menoleransi pesan duplikat. Jika urutan diperlukan, subsistem dapat mengimplementasikan teknik agregasi dan windowing; namun, pendekatan ini mengorbankan skalabilitas dan ketersediaan dalam komponen tersebut.

Teknik pemfilteran dan fanout

Karena aliran peristiwa dapat berisi data yang mungkin diperlukan atau tidak diperlukan oleh setiap pelanggan, sering kali ada kebutuhan untuk membatasi data yang diterima pelanggan tertentu. Ada dua pola untuk mengelola persyaratan ini: filter peristiwa dan fanout peristiwa.

Diagram berikut menunjukkan sistem berbasis peristiwa dengan filter peristiwa yang memfilter pesan untuk pelanggan:

Model berbasis peristiwa dengan filter peristiwa yang memfilter pesan ke pelanggan.

Pada diagram sebelumnya, filter peristiwa menggunakan mekanisme pemfilteran yang membatasi peristiwa yang menjangkau pelanggan. Dalam model ini, satu topik berisi semua variasi pesan. Pelanggan tidak akan membaca setiap pesan dan memverifikasi apakah pesan tersebut berlaku, akan tetapi logika pemfilteran dalam sistem pesan akan mengevaluasi pesan tersebut dan menjaganya dari pelanggan lainnya.

Diagram berikut menunjukkan variasi pola filter peristiwa yang disebut fanout peristiwa, yang menggunakan beberapa topik:

Model berbasis peristiwa dengan fanout peristiwa yang memublikasikan ulang pesan berdasarkan berbagai topik.

Dalam diagram sebelumnya, topik utama berisi semua variasi pesan, tetapi mekanisme fanout peristiwa akan memublikasikan ulang pesan tentang topik yang terkait dengan sebagian subscriber tersebut.

Antrean pesan yang belum diproses

Bahkan dalam sistem terbaik pun, kegagalan dapat terjadi. Antrean pesan yang belum diproses adalah teknik untuk menangani kegagalan semacam itu. Pada sebagian besar arsitektur berbasis peristiwa, sistem pesan akan terus memberikan pesan kepada pelanggan hingga dikonfirmasi oleh pelanggan.

Jika ada masalah dengan pesan—misalnya, karakter yang tidak valid dalam isi pesan—pelanggan mungkin tidak dapat mengonfirmasi pesan tersebut. Sistem dapat gagal menangani skenario atau bahkan dapat menghentikan proses.

Sistem biasanya mencoba kembali pesan yang tidak terkonfirmasi atau salah. Jika pesan yang tidak valid tidak dikonfirmasi setelah jangka waktu yang ditentukan, pesan akan kehabisan waktu dan dihapus dari topik. Dari sudut pandang operasional, sebaiknya tinjau pesan agar tidak hilang. Di sinilah antrean pesan yang belum diproses akan masuk. Pesan tidak dihapus dari topik, tetapi pesan akan dipindahkan ke topik lain yang dapat diproses ulang atau ditinjau untuk memahami penyebab error.

Histori streaming dan replay

Aliran peristiwa adalah alur data yang sedang berlangsung. Akses ke data historis ini sangat berguna. Anda mungkin ingin tahu bagaimana sistem mencapai status tertentu. Anda mungkin memiliki pertanyaan terkait keamanan yang memerlukan audit data. Mampu menangkap log historis dari peristiwa sangat penting dalam operasi jangka panjang dari sistem berbasis peristiwa.

Salah satu penggunaan umum data peristiwa historis adalah menggunakannya dengan sistem replay. Replay digunakan untuk tujuan pengujian. Dengan memutar ulang data peristiwa dari produksi di lingkungan lain seperti tahap dan pengujian, Anda dapat memvalidasi fungsi baru berdasarkan set data sebenarnya. Anda juga dapat memutar ulang data historis untuk pulih dari status gagal. Jika sistem tidak aktif atau kehilangan data, tim dapat memutar ulang histori peristiwa dari titik akurat yang diketahui dan layanan dapat membangun ulang status yang hilang.

Merekam peristiwa ini dalam antrean berbasis log atau streaming log juga berguna saat pelanggan memerlukan akses ke urutan peristiwa pada waktu yang berbeda. Streaming logging dapat dilihat dalam sistem dengan kemampuan offline. Dengan menggunakan histori streaming, Anda dapat memproses entri baru terbaru dengan membaca streaming yang dimulai dari pointer terakhir dibaca.

Tampilan data: real time dan mendekati real-time

Dengan semua data yang mengalir melalui sistem, penting bagi Anda untuk dapat menggunakan data. Ada banyak teknik untuk mengakses dan menggunakan aliran data peristiwa ini, tetapi kasus penggunaan yang umum adalah memahami status data secara keseluruhan pada momen tertentu. Hal ini sering kali berupa pertanyaan yang berorientasi pada perhitungan, seperti "berapa banyak" atau "tingkat saat ini" yang dapat digunakan oleh sistem lain atau untuk konsumsi manusia. Ada beberapa implementasi yang dapat menjawab pertanyaan-pertanyaan berikut:

  • Sistem real-time dapat berjalan secara terus-menerus dan melacak status saat ini; tetapi, karena sistem hanya memiliki penghitungan dalam memori, periode nonaktif apa pun akan menetapkan penghitungan ke nol.
  • Sistem dapat menghitung nilai dari tabel histori untuk setiap permintaan, tetapi hal ini bisa menjadi masalah karena mencoba menghitung nilai untuk setiap permintaan selagi data sedang berkembang pada akhirnya semakin tidak mungkin dilakukan.
  • Sistem dapat membuat snapshot penghitungan pada interval tertentu, tetapi hanya menggunakan snapshot semata tidak akan mencerminkan data yang real-time.

Pola yang berguna untuk diimplementasikan adalah Arsitektur Lambda dengan kemampuan yang mendekati real-time dan real-time. Misalnya, halaman produkinfeasibledi situs e-commerce dapat menggunakan tampilan data inventaris yang hampir real-time. Saat pelanggan melakukan pemesanan, layanan real-time digunakan untuk memastikan pembaruan status data inventaris terbaru. Untuk menerapkan pola ini, layanan ini merespons permintaan hampir real-time dari tabel snapshot yang berisi nilai kalkulasi pada interval tertentu. Permintaan real-time menggunakan tabel snapshot dan nilai dalam tabel histori sejak snapshot terakhir untuk mendapatkan status saat ini yang tepat. Tampilan terwujud dari aliran peristiwa ini memberikan data yang dapat ditindaklanjuti untuk mendorong proses bisnis yang nyata.

Langkah selanjutnya