3.12 Arsitektur berbasis peristiwa dan pesan
Tinjauan dan motivasi
Arsitektur berbasis peristiwa (event-driven architecture, EDA) adalah gaya di mana komponen berkomunikasi dengan menghasilkan dan bereaksi terhadap peristiwa alih-alih saling memanggil secara langsung. Peristiwa adalah fakta: sesuatu yang sudah terjadi, seperti “OrderPlaced” atau “PaymentCaptured.” Produsen mengumumkan fakta itu lalu melanjutkan, dan sejumlah konsumen bereaksi sesuai jadwal mereka sendiri tanpa produsen mengetahui siapa yang mendengarkan. Ini sikap yang berbeda dari panggilan permintaan-dan-balasan di bab 2.3, di mana pemanggil meminta layanan tertentu melakukan sesuatu dan menunggu jawabannya.
Bagi organisasi besar, daya tariknya adalah pemisahan pada skala besar. Ketika Anda punya puluhan tim dan ratusan layanan, mengkabel semuanya dengan panggilan titik-ke-titik langsung menghasilkan jaring rapuh di mana perubahan satu tim merusak tim lain dan tak seorang pun dapat melacak sebabnya. Peristiwa memungkinkan tim berintegrasi lewat aliran fakta bersama alih-alih lewat internal satu sama lain, dan konsumen baru bergabung dengan berlangganan, tanpa produsen mengubah satu baris kode. Sifat itu, lebih daripada throughput mentah, adalah alasan pendekatan berbasis peristiwa terus menyebar di enterprise yang menggantikan integrasi kusut dan pemerintah yang menyatukan lembaga yang masing-masing memiliki sistemnya sendiri.
Sektor publik mendapat manfaat kedua yang mudah diremehkan: catatan tahan lama dan berurutan tentang apa yang terjadi adalah aset audit dan transparansi. Ketika warga bertanya mengapa keputusan tunjangan berakhir seperti itu, log tak berubah dari peristiwa yang mengarah kepadanya menjawab langsung. Tetapi desain berbasis peristiwa tidak gratis dan tidak selalu tepat: alur asinkron lebih sulit dilacak, lebih sulit dinalar, dan mudah diterapkan berlebihan. Bab ini berpendirian tentang kapan pemisahan dan skala membayar kompleksitas tambahan, dan kapan panggilan sinkron biasa akan melayani Anda lebih baik. Ia bertumpu pada kenyataan sistem terdistribusi di bab 3.3, jadi baca itu dulu jika belum.
Prinsip utama
- Peristiwa adalah fakta, bukan instruksi. Peristiwa mengatakan apa yang terjadi; perintah meminta sesuatu terjadi. Jaga keduanya tetap berbeda, dan namai peristiwa dalam bentuk lampau.
- Pemisahan (decoupling) adalah intinya. Produsen tidak boleh tahu atau peduli siapa yang mengonsumsi peristiwanya. Jika mereka peduli, Anda punya kopling yang mengenakan kostum pesan.
- Rancang untuk pengiriman setidaknya-sekali. Pengiriman tepat-sekali adalah mitos. Buat setiap konsumen idempoten agar duplikat tidak berbahaya.
- Urutan adalah jaminan yang Anda bayar. Anda mendapat urutan dalam partisi, bukan lintas topik. Pilih kunci partisi dengan sengaja.
- Skema adalah kontrak. Bentuk peristiwa adalah antarmuka publik; kembangkan dengan kehati-hatian yang akan Anda berikan pada API yang diterbitkan.
- Asinkron tidak berarti tak dapat diobservasi. Jika Anda tidak dapat mengikuti pesan dari ujung ke ujung, Anda tidak dapat mengoperasikan sistem.
- Kompleksitas harus diperoleh. Event sourcing, CQRS, dan saga ampuh dan mahal; raih ketika masalah menuntutnya, bukan secara bawaan.
Rekomendasi
Bedakan peristiwa, perintah, dan pesan sebelum membangun apa pun
Ketiga kata ini dipakai bergantian, dan kebingungannya menyebabkan kesalahan desain nyata. Perintah (command) adalah permintaan melakukan sesuatu (“CapturePayment”), ditujukan pada satu penangan, dan dapat ditolak. Peristiwa (event) adalah pemberitahuan bahwa sesuatu sudah terjadi (“PaymentCaptured”), disiarkan kepada siapa pun yang berminat, dan tidak dapat ditolak karena faktanya sudah benar. Pesan (message) adalah amplop netral yang membawa salah satunya lewat kabel. Pembedaan ini membentuk kopling: perintah mengopel pengirim ke penerima dan hasil tertentu, sedangkan peristiwa melepas kendali atas apa yang terjadi berikutnya. Namai peristiwa Anda dalam bentuk lampau, dan ketika Anda mendapati diri menerbitkan “peristiwa” yang sebenarnya berarti “tolong lakukan hal spesifik ini,” Anda telah menulis perintah yang menyamar.
Pilih antrean, log, dan publish/subscribe dengan sengaja
Tidak semua pesan berbentuk sama, dan memilih yang salah adalah kesalahan awal yang umum. Antrean pesan mengirim setiap pesan ke satu konsumen dan biasanya menghapusnya setelah diproses, yang cocok untuk distribusi kerja: banyak pekerja menarik tugas, masing-masing dikerjakan sekali. Log peristiwa tahan lama (aliran) menyimpan peristiwa secara berurutan dan memungkinkan banyak konsumen independen membaca pada laju mereka sendiri, memutar ulang riwayat dari titik mana pun, yang cocok untuk distribusi peristiwa dan audit. Publish/subscribe membuat produsen menerbitkan ke topik dan banyak pelanggan masing-masing mendapat salinannya sendiri. Aturan praktisnya: jika pesan adalah tugas yang harus diselesaikan satu pekerja, raih antrean; jika ia fakta yang mungkin diperhatikan banyak pihak sekarang atau nanti, raih log tahan lama, yang juga memberi Anda pemutaran ulang untuk pemulihan dan onboarding konsumen baru. Lihat bab 3.4 untuk bagaimana pilihan ini berinteraksi dengan strategi penyimpanan data Anda.
Pilih koreografi untuk otonomi, orkestrasi untuk kendali
Ketika proses bisnis mencakup beberapa layanan, Anda mengoordinasikannya dengan salah satu dari dua cara. Dalam koreografi, setiap layanan bereaksi terhadap peristiwa dan memancarkan peristiwanya sendiri, tanpa otak pusat: terpisah maksimal dan baik untuk otonomi tim, tetapi proses keseluruhan hanya ada sebagai perilaku emergen yang tak dijelaskan satu tempat pun. Dalam orkestrasi, koordinator pusat menggerakkan langkah-langkah dan mengetahui seluruh alur: lebih mudah dipantau dan diubah, dengan biaya komponen yang menjadi sandaran setiap langkah. Bawaan yang baik adalah koreografi untuk reaksi yang longgar terkait (“ketika pesanan dikirim, layanan loyalitas memberi poin”) dan orkestrasi untuk transaksi terdefinisi dengan kondisi sukses jelas dan kebutuhan melaporkan status. Jangan biarkan proses penting hidup hanya sebagai pengetahuan suku yang tersebar di sepuluh penangan peristiwa.
Raih event sourcing dan CQRS hanya ketika layak biayanya
Event sourcing menyimpan status sebagai urutan peristiwa append-only alih-alih snapshot saat ini yang Anda timpa, dan Anda membangun ulang status saat ini dengan memutar ulangnya. Keuntungannya jejak audit sempurna, kemampuan merekonstruksi status masa lalu mana pun, dan kueri temporal; biayanya Anda memversikan skema peristiwa selamanya, menangani pemutaran ulang dan snapshot, dan membawa model mental yang belum pernah dipakai kebanyakan pengembang. CQRS (Command Query Responsibility Segregation) memisahkan model tulis dari satu atau lebih model baca agar pembacaan dan penulisan berskala dan berkembang secara independen; ia berpasangan alami dengan event sourcing tetapi tidak mewajibkannya. Keduanya bersinar untuk domain dengan kebutuhan audit, kepatuhan, atau kueri kompleks yang sejati, itulah mengapa keuangan dan pemerintah teregulasi menganggapnya sepadan dengan repotnya. Untuk layanan create-read-update-delete sederhana, keduanya kompleksitas tak sengaja yang akan Anda sesali, jadi terapkan pada irisan domain Anda yang membutuhkannya, bukan seluruh sistem secara refleks.
Kelola transaksi terdistribusi dengan saga, bukan two-phase commit
Anda biasanya tidak dapat membungkus satu transaksi atomik di sekitar beberapa layanan dan basis data. Two-phase commit terdistribusi menahan kunci melintasi jaringan, memotong ketersediaan, dan berskala buruk, sehingga jarang cocok dengan sistem berbasis peristiwa. Pola saga menggantikannya: modelkan transaksi sebagai urutan transaksi lokal, masing-masing memancarkan peristiwa yang memicu berikutnya, dan beri setiap langkah tindakan kompensasi yang membatalkannya jika langkah berikutnya gagal. Jika “reserve inventory” berhasil tetapi “charge card” gagal, kompensasi melepaskan inventaris. Saga dapat dikoreografikan atau diorkestrasi, dan orkestrasi biasanya menang untuk apa pun yang harus Anda pantau. Karena saga merangkul konsistensi akhirnya, sistem melewati keadaan antara (“dipesan tetapi belum dibayar”) sebelum konvergen, jadi rancang pengalaman pengguna dan jejak audit Anda untuk menampilkan keadaan “sedang berjalan” dan “dikompensasi” dengan jujur. Bab 3.3 membahas wilayah yang sama dari sudut sistem terdistribusi.
Rancang untuk pengiriman setidaknya-sekali dan jadikan konsumen idempoten
Sistem pesan tidak dapat benar-benar mengirim tepat-sekali melintasi kegagalan, karena pengakuan yang berkata “saya sudah memproses ini” dapat hilang sendiri, memaksa pengiriman ulang. Yang dapat Anda capai adalah pengiriman setidaknya-sekali dengan pemrosesan idempoten, yang menghasilkan efek tepat-sekali. Idempotensi berarti memproses peristiwa yang sama dua kali menghasilkan hasil yang sama seperti memprosesnya sekali; capai dengan kunci idempotensi pada setiap peristiwa dan catatan apa yang telah Anda tangani, sehingga duplikat dikenali dan dibuang. Pengiriman paling-banyak-sekali (kirim dan lupakan, tanpa pengiriman ulang) lebih sederhana tetapi diam-diam kehilangan pesan, jadi sisihkan untuk data yang sanggup Anda hilangkan. Perlakukan label “tepat-sekali” yang diiklankan sebagian vendor dengan kecurigaan: biasanya berarti tepat-sekali dalam batas satu sistem pada kondisi tertentu, bukan jaminan ujung ke ujung yang tersirat dalam frasa itu.
Kendalikan urutan dengan partisi, dan kenali grup konsumen Anda
Urutan tidak global dan gratis; ia lokal dan dibayar. Aliran dipecah menjadi partisi, dan Anda mendapat urutan dalam partisi, bukan lintas topik. Peristiwa dirutekan ke partisi menurut kunci partisi, jadi memilih kunci itu adalah cara Anda mengendalikan apa yang tetap berurutan: kunci menurut ID pelanggan dan peristiwa satu pelanggan tetap berurutan satu sama lain, sementara pelanggan berbeda diproses paralel. Grup konsumen memungkinkan sekumpulan pekerja berbagi partisi sebuah topik, setiap partisi ditangani satu pekerja, yaitu cara Anda menskalakan throughput sambil mempertahankan urutan per partisi; di sinilah skalabilitas bertemu kebenaran, terhubung ke bab 3.5. Pilih kunci partisi yang mencerminkan persyaratan urutan nyata Anda dan menyebar beban merata, karena kunci yang menyalurkan sebagian besar lalu lintas ke satu partisi menciptakan titik panas yang tak dapat diredakan oleh pekerja sebanyak apa pun.
Perlakukan skema sebagai kontrak dengan registri dan aturan evolusi
Struktur peristiwa adalah antarmuka terbit yang dikonsumsi tim yang mungkin tak pernah Anda temui, jadi mengubahnya sembarangan merusak mereka dari kejauhan. Taruh skema peristiwa Anda dalam schema registry, katalog bersama yang menyimpan setiap skema dan menegakkan aturan kompatibilitas ketika produsen mencoba mengubahnya. Adopsi kebijakan eksplisit: perubahan kompatibel mundur (menambah bidang opsional) diizinkan; perubahan yang merusak (menghapus bidang, mengubah tipe, mengganti nama) memerlukan versi skema baru dan rencana migrasi. Ini memungkinkan produsen berkembang tanpa deploy tersinkron di setiap konsumen, yang persis alasan Anda memilih peristiwa. Disiplin pembuatan versi antarmuka dari bab 2.3 berlaku, karena skema peristiwa adalah API dengan nama lain.
Jamin pengiriman dengan transactional outbox, dan tangani kegagalan secara eksplisit
Bug klasik: layanan Anda menulis ke basis data lalu menerbitkan peristiwa, dan crash di antara keduanya, sehingga basis data berubah tetapi peristiwa tak pernah keluar. Transactional outbox memperbaikinya dengan menulis peristiwa ke tabel outbox dalam transaksi basis data yang sama dengan perubahan status, sehingga keduanya berhasil atau gagal bersama; relay terpisah kemudian membaca outbox dan menerbitkan ke broker, sering memakai change data capture untuk mengekor log basis data. Untuk kegagalan konsumsi, dead letter queue menahan pesan yang berulang kali gagal agar poison message (yang tak akan pernah berhasil, mungkin karena cacat bentuk) tidak memblokir antrean di belakangnya selamanya. Tambahkan backpressure agar produsen cepat tidak membanjiri konsumen lambat: batasi antrean Anda, dan perlambat atau lepas beban ketika penuh alih-alih menghabiskan memori. Keempat mekanisme ini memisahkan demo dari sistem yang dapat Anda jalankan pukul 3 pagi.
Buat alur asinkron dapat diobservasi dari ujung ke ujung
Biaya tersulit beralih ke berbasis peristiwa adalah bahwa satu tindakan bisnis kini tersebar di produsen, broker, dan konsumen tanpa tumpukan panggilan yang mengikatnya. Rambatkan ID korelasi melalui setiap peristiwa agar Anda dapat mengikuti satu alur logis di setiap lompatan, disiplin yang sama yang ditetapkan bab 3.3 untuk panggilan sinkron. Lacak lag konsumen (seberapa jauh tertinggal dari waktu nyata setiap konsumen membaca) sebagai metrik kelas satu, karena lag yang naik adalah peringatan paling awal Anda akan masalah, dan pantau kedalaman dead letter queue, latensi pemrosesan, dan tingkat pengiriman ulang. Tanpa ini, peristiwa yang diam-diam gagal dikonsumsi menjadi bug tak terlihat yang muncul berhari-hari kemudian sebagai data hilang.
Trade-off: kelebihan dan kekurangan
| Pendekatan | Kelebihan | Kekurangan / biaya |
|---|---|---|
| Permintaan/balasan sinkron | Sederhana dinalar, hasil segera, pelacakan mudah | Kopling temporal ketat, kegagalan berantai, skala terbatas |
| Berbasis peristiwa (pub/sub di atas log) | Pemisahan, penskalaan independen, pemutaran ulang, jejak audit | Konsistensi akhirnya, pelacakan lebih sulit, lebih banyak bagian bergerak |
| Antrean pesan (distribusi kerja) | Perataan beban, penyangga, ramah backpressure | Satu konsumen per pesan, kurang cocok untuk siaran |
| Event sourcing + CQRS | Riwayat penuh, kueri temporal, baca/tulis berskala independen | Pembuatan versi skema selamanya, kompleksitas pemutaran ulang, kurva belajar curam |
| Saga (vs two-phase commit) | Skalabel, tersedia, tanpa lock terdistribusi | Konsistensi akhirnya, logika kompensasi, lebih sulit dinalar |
Ketegangan pusatnya adalah antara pemisahan dan keterpahaman. Setiap peristiwa yang Anda tambah mengendurkan kopling antara produsen dan konsumen, membeli otonomi tim dan penskalaan independen, dan pada saat yang sama menghapus satu baris cerita yang akan dikatakan panggilan sinkron dengan jelas: alur menjadi emergen, hidup dalam interaksi alih-alih dalam satu berkas pun. Selesaikan dengan selektif: pakai peristiwa di tempat pemisahan benar-benar membayar, seperti integrasi lintas batas tim, penyebaran ke banyak konsumen, penyangga lonjakan beban, dan audit. Pertahankan panggilan sinkron di tempat Anda membutuhkan jawaban segera dan model mental sederhana, seperti membaca data untuk merender halaman. Mode kegagalan yang harus dihindari adalah mengubah setiap panggilan fungsi internal menjadi peristiwa lalu menyebutnya arsitektur, penilaian arsitektural yang sama yang diminta bab 3.2 dari setiap pola yang Anda adopsi.
Pertanyaan untuk didiskusikan dengan tim Anda
Untuk interaksi spesifik ini, apakah kita benar-benar membutuhkan peristiwa, atau panggilan sinkron akan lebih jelas dan lebih aman? Melewatkan pertanyaan ini adalah cara sistem menumpuk kompleksitas tak sengaja. Ujian jujurnya adalah apakah produsen membutuhkan hasil kembali sekarang juga (panggilan) atau mengumumkan fakta yang mungkin ditanggapi pihak lain pada waktu mereka sendiri (peristiwa). Bawa interaksi spesifik, bukan preferensi umum, dan tanyakan pemisahan apa yang Anda peroleh dan kejelasan pelacakan apa yang Anda lepas. Jika pemanggil memblokir menunggu “peristiwa” diproses, Anda telah membangun panggilan sinkron yang lambat dan sulit di-debug dan membayar ekstra untuk kehormatan itu. Bawaan untuk interaksi internal, satu tim, butuh-jawaban-sekarang seharusnya panggilan langsung; sisihkan peristiwa untuk tempat kopling longgar layak biayanya.
Apa yang terjadi ketika konsumen menerima peristiwa yang sama dua kali, dan sudahkah kita benar-benar mengujinya? Pengiriman setidaknya-sekali menjamin duplikat akan terjadi, sehingga setiap konsumen harus idempoten, namun idempotensi mudah diklaim dan mudah keliru. Telusuri konsumen nyata dan lacak persis bagaimana pengiriman kedua dikenali dan dinetralkan, apakah lewat kunci idempotensi, log peristiwa yang diproses, atau operasi yang secara alami idempoten. Bawa hasil tes sebenarnya di mana Anda mengirim ulang batch dan memastikan tidak ada tagihan ganda, catatan duplikat, atau notifikasi berulang. Beri perhatian khusus pada efek samping yang meninggalkan basis data Anda, seperti email, pembayaran, dan panggilan pihak ketiga, karena di situlah bug tak idempoten langsung menyakiti pelanggan. Jika tim Anda tidak dapat menunjuk tes yang membuktikan keamanan-duplikat, asumsikan Anda tidak aman-duplikat.
Ketika alur peristiwa rusak di produksi, berapa lama sampai kita menyadarinya, dan dapatkah kita melacak satu pesan dari ujung ke ujung? Kegagalan asinkron senyap, sehingga konsumen yang diam-diam berhenti memproses dapat tak terdeteksi sampai data hilang menjadi keluhan pelanggan atau celah audit. Tanyakan apa sinyal paling awal Anda, dan apakah Anda memantau lag konsumen dan kedalaman dead letter queue sebagai metrik peringatan alih-alih dasbor yang tak ditonton siapa pun. Bawa insiden nyata atau latihan game day dan ukur berapa lama mengikuti satu ID korelasi melintasi produsen, broker, dan setiap konsumen. Jika jawabannya “kami men-grep beberapa layanan dan menebak,” observabilitas Anda belum siap untuk kompleksitas yang telah Anda ambil. Di sektor teregulasi, kemampuan merekonstruksi persis bagaimana pesan bergerak sering kali persyaratan kepatuhan, bukan basa-basi.
Bagaimana kita akan mengembangkan skema peristiwa yang sudah dikonsumsi banyak tim tanpa merusak satu pun dari mereka? Bentuk peristiwa adalah kontrak publik, dan begitu puluhan konsumen bergantung padanya, perubahan yang tampak tak bersalah dapat merusak sistem yang belum pernah Anda dengar, dari kejauhan, tanpa kompiler yang memperingatkan. Ketegangannya nyata: produsen ingin bergerak cepat dan merapikan peristiwa mereka, sementara setiap konsumen ingin bentuknya dibekukan selamanya, jadi sepakati di muka perubahan mana yang aman (menambah bidang opsional) dan mana yang menuntut versi baru dan jendela migrasi (menghapus bidang, mengubah tipe, mengganti nama). Bawa daftar konsumen sebenarnya per topik, apakah schema registry menegakkan aturan kompatibilitas hari ini atau bentuk berubah lewat kesepakatan informal, dan berapa lama dua versi dapat berjalan paralel selama migrasi. Dalam enterprise besar atau pengaturan berbagi data pemerintah lintas lembaga, skema yang rusak diam-diam dapat merusak catatan di sistem yang tidak Anda miliki dan muncul kemudian sebagai kegagalan audit, jadi perlakukan penegakan kompatibilitas sebagai tata kelola, bukan kesopanan.
Untuk transaksi multilayanan terpenting kita, apa yang sebenarnya dibatalkan setiap tindakan kompensasi, dan keadaan antara apa yang akan dilihat pengguna dan auditor? Saga menukar ilusi menenangkan satu transaksi atomik dengan urutan langkah lokal yang masing-masing dapat gagal, sehingga sistem benar-benar melewati keadaan seperti “dipesan tetapi belum dibayar” dan “ditagih tetapi belum dikirim” sebelum konvergen, dan berpura-pura sebaliknya adalah cara mengirim saga yang membocorkan uang atau menelantarkan catatan. Telusuri proses nyata dari ujung ke ujung, namai kompensasi untuk setiap langkah (apa yang melepas inventaris, apa yang mengembalikan dana kartu), dan putuskan apakah saga terorkestrasi yang dapat Anda pantau mengalahkan koreografi emergen yang tak dijelaskan satu tempat pun. Bawa kasus kegagalan yang benar-benar telah diuji, bukan jalur bahagia, dan pastikan pengalaman pengguna dan jejak audit menampilkan keadaan “sedang berjalan” dan “dikompensasi” dengan jujur alih-alih menyembunyikannya. Dalam sistem keuangan, tunjangan, atau pajak, regulator akan menanyakan seperti apa catatan pada setiap momen antara dan siapa yang bertanggung jawab atas kompensasi, sehingga keadaan saga sendiri adalah artefak kepatuhan.
Siapa yang menjalankan broker atau log peristiwa, dan sudahkah kita menghitung biaya sebenarnya mengoperasikannya terhadap alternatif terkelola? Tulang punggung pesan bukan infrastruktur gratis yang muncul begitu Anda menggambarnya di diagram: seseorang menambalnya, menskalakan partisinya, menyetel retensinya, merespons ketika ia memanggil pukul 3 pagi, dan memiliki kapasitas serta mode kegagalannya. Putuskan dengan sengaja antara menjalankan sendiri broker sumber terbuka dan membeli layanan terkelola, menimbang kendali dan residensi data terhadap beban operasional dan biaya lisensi, dan jujurlah apakah tim Anda punya kedalaman untuk menjalankan log terdistribusi dengan baik. Bawa total biaya kepemilikan: beban on-call, keahlian spesialis yang dibutuhkan, tagihan retensi dan penyimpanan, dan apa yang dilakukan pemadaman broker pada setiap alur yang bergantung. Untuk enterprise jawabannya membentuk mandat tim platform, dan untuk badan pemerintah aturan pengadaan, persyaratan kedaulatan data, dan kebutuhan keras menghindari lock-in vendor dapat mengalahkan opsi termurah, jadi munculkan kendala itu sebelum berkomitmen pada teknologi yang akan Anda jalankan selama satu dekade.
Lensa sektor
Startup. Sumber daya Anda yang paling langka adalah perhatian rekayasa, jadi tetaplah sinkron sampai penyebaran benar-benar menyakitkan. Ketika tiga hal perlu bereaksi terhadap satu tindakan, terbitkan satu peristiwa (seperti “OrderPlaced”) ke antrean atau log terkelola alih-alih mendirikan klaster broker sendiri, dan pertahankan pembayaran serta apa pun yang butuh jawaban segera sebagai panggilan langsung. Jangan mengadopsi event sourcing, CQRS, atau saga agar tampak canggih; kompleksitas itu akan melampaui tim kecil dan memperlambat iterasi yang justru menjadi arena persaingan Anda.
Bisnis kecil. Anda tidak punya spesialis pesan dan tidak berselera menjalankan Kafka, jadi perlakukan integrasi asinkron sebagai sesuatu yang Anda beli, bukan operasikan. Bersandarlah pada peristiwa yang sudah dipancarkan perkakas Anda (webhook, antrean bawaan penyedia cloud atau platform SaaS Anda) dan biarkan layanan terkelola memiliki pengiriman, retensi, dan perpipaan idempotensi. Bingkai pilihan sebagai beli-versus-bangun dengan jujur: segelintir penangan webhook yang andal mengalahkan broker pesanan yang tak sanggup Anda isi stafnya atau debug pukul 3 pagi.
Enterprise. Masalah Anda adalah biaya integrasi di banyak tim, jadi imbalannya adalah platform bersama yang diatur: log peristiwa tahan lama, schema registry dengan kebijakan kompatibilitas yang ditegakkan, kepemilikan topik yang jelas, dan pola idempotensi serta outbox standar agar setiap tim tidak menciptakannya ulang. Inilah pengaturan di mana mengganti enterprise service bus yang rapuh atau jaring tautan titik-ke-titik berlipat menjadi penghematan nyata, dan di mana saga terorkestrasi dengan status terlihat memungkinkan staf operasi mengelola proses multilangkah. Anggarkan investasi observabilitas dan tata kelola skema secara eksplisit, karena pada skala ini kegagalan konsumen yang senyap menjadi data hilang di puluhan sistem.
Pemerintah. Log peristiwa tahan lama dan berurutan adalah aset audit dan transparansi: ia menjawab “mengapa keputusan ini berakhir seperti ini” dengan urutan fakta tak berubah, jadi condonglah ke event sourcing di tempat akuntabilitas menuntutnya. Berbagi data antarlembaga membutuhkan pengiriman setidaknya-sekali dengan deduplikasi pada ID peristiwa yang stabil agar catatan yang dikirim ulang tidak pernah membuat kasus duplikat, dan pengadaan harus menimbang kedaulatan data, pengungkapan keterbatasan broker, dan portabilitas terhadap lock-in. Terbitkan, bila sesuai, bagaimana alur bekerja dan bagaimana warga dapat menggugat hasil otomatis, dan jaga log peristiwa sebagai catatan yang dapat dipertahankan yang akan diminta untuk diperiksa badan pengawas.
Contoh
Startup. Sebuah startup e-commerce kecil mulai dengan satu alur sinkron: checkout memanggil layanan pembayaran dan menunggu. Seiring tumbuh, ia ingin email konfirmasi pesanan, pembaruan inventaris, dan program loyalitas bereaksi terhadap pembelian, dan mengkabel masing-masing sebagai panggilan sinkron lain di dalam checkout membuat checkout lambat dan rapuh. Tim menerbitkan satu peristiwa “OrderPlaced” ke log tahan lama dan membiarkan tiga konsumen independen bereaksi, sehingga checkout cepat lagi dan menambah reaksi keempat kelak tidak memerlukan perubahan apa pun padanya. Mereka mempertahankan penangkapan pembayaran sinkron, karena mereka butuh jawaban ya-atau-tidak sebelum mengonfirmasi pesanan, yang persis garis yang tepat untuk ditarik pada ukuran mereka.
Enterprise. Sebuah perusahaan asuransi global tenggelam dalam integrasi titik-ke-titik dan enterprise service bus (ESB) yang menua, hub pusat yang dilalui setiap sistem dan yang telah menjadi hambatan dan titik kegagalan tunggal. Ia bermigrasi ke log peristiwa tahan lama di mana setiap domain menerbitkan faktanya (polis diterbitkan, klaim diajukan, pembayaran dilakukan) dan tim konsumen berlangganan apa yang mereka butuhkan. Saga klaim, diorkestrasi agar staf operasi dapat melihat status setiap klaim, mengoordinasikan penyelesaian multilangkah dengan kompensasi untuk langkah yang gagal. Schema registry memungkinkan tim polis mengembangkan peristiwanya tanpa deploy tersinkron di empat puluh sistem konsumen, persis kerapuhan yang dipaksakan ESB lama.
Pemerintah. Sebuah otoritas pajak nasional harus memberi warga dan auditor jawaban yang dapat dipertahankan atas “mengapa penilaian saya berakhir seperti ini.” Ia memodelkan domain penilaian dengan event sourcing, sehingga setiap perubahan adalah peristiwa tak berubah dalam log berurutan dan penilaian saat ini adalah pemutaran ulang peristiwa itu; ketika warga menyengketakan angka, petugas kasus merekonstruksi status persis pada tanggal masa lalu mana pun dan menunjukkan urutan fakta yang menghasilkannya. Berbagi data antarlembaga berjalan di atas topik tahan lama dengan pengiriman setidaknya-sekali, dan konsumen setiap lembaga melakukan deduplikasi pada ID peristiwa sehingga catatan yang dikirim ulang tidak pernah membuat kasus duplikat. Log peristiwa sekaligus menjadi jejak audit yang dituntut badan pengawas, mengubah kewajiban kepatuhan menjadi produk sampingan desain.
Kasus bisnis: motivasi, ROI, dan TCO
Imbal hasil arsitektur berbasis peristiwa didominasi satu hal: biaya integrasi seiring waktu. Integrasi titik-ke-titik membuat biaya itu tumbuh seiring jumlah sambungan, yang tumbuh lebih cepat daripada jumlah sistem, sehingga integrasi menjadi pajak yang memakan kapasitas pengiriman Anda. Peristiwa meratakannya, karena tim berintegrasi lewat aliran fakta bersama, konsumen baru bergabung dengan berlangganan, dan produsen berkembang di balik skema berversi, sehingga biaya marginal integrasi berikutnya turun tajam. Itulah kisah ROI inti untuk disampaikan kepada pimpinan: bukan kinerja mentah, melainkan pengurangan berlipat dalam biaya perubahan di banyak tim.
Namai total biaya kepemilikan dengan jujur agar Anda dipercaya. Anda mengambil infrastruktur broker untuk dijalankan, tata kelola skema untuk dipelihara, dan kurva belajar operasional lebih curam, karena sistem asinkron benar-benar lebih sulit di-debug, jadi anggarkan investasi observabilitas di muka. Timbang ini terhadap biaya tidak mengadopsi peristiwa di tempat yang cocok: lapisan integrasi yang membatu di mana setiap perubahan adalah proyek koordinasi multitim, ESB warisan yang menjadi hambatan yang tak berani disentuh siapa pun, dan ketidakmampuan menambah kemampuan tanpa mengganggu yang lama. Bagi enterprise yang mengganti pengkabelan titik-ke-titik yang rapuh dan pemerintah yang membangun jejak audit tahan lama, imbalannya terkuat di tempat kebutuhan audit dan pemisahan nyata. Di tempat kebutuhan itu tidak ada, jawaban jujurnya adalah desain sinkron yang lebih sederhana memiliki TCO lebih rendah, dan Anda harus mengatakannya.
Anti-pola dan jebakan
- Monolit terdistribusi yang menyamar. Layanan yang harus di-deploy bersama dan bergantung pada peristiwa internal satu sama lain. Anda menambah broker tetapi mempertahankan kopling, sehingga Anda mendapat kekurangan kedua gaya.
- Peristiwa sebagai perintah. Menerbitkan “peristiwa” yang sebenarnya berarti “tolong lakukan hal spesifik ini untuk saya,” menciptakan ulang kopling ketat dengan latensi tambahan dan keterlacakan lebih buruk.
- Mengasumsikan pengiriman tepat-sekali. Konsumen yang rusak, menagih ganda, atau menduplikasi catatan ketika broker pasti mengirim ulang pesan.
- Event sourcing untuk segalanya. Menerapkan event sourcing dan CQRS pada domain create-read-update-delete sederhana yang tak pernah butuh riwayat, membeli kompleksitas curam tanpa manfaat.
- Tanpa tata kelola skema. Produsen mengubah bentuk peristiwa dengan bebas, merusak konsumen hilir dari kejauhan tanpa pemeriksaan kompatibilitas.
- Mengabaikan outbox. Menulis ke basis data dan menerbitkan peristiwa sebagai dua langkah terpisah, sehingga crash di antaranya diam-diam kehilangan peristiwa atau memancarkan yang hantu.
- Tanpa penanganan dead letter. Satu poison message memblokir partisi, atau pesan gagal lenyap tanpa antrean untuk menangkap dan memeriksanya.
- Alur tak terlihat. Pemrosesan asinkron tanpa ID korelasi, tanpa peringatan lag konsumen, dan tanpa pelacakan, sehingga kegagalan tetap senyap sampai menjadi data hilang.
Model kematangan
- Tingkat 1, Memulai: Integrasi berupa panggilan titik-ke-titik ad hoc, atau broker ada tetapi dipakai seperti permintaan/balasan sinkron. Duplikat merusak konsumen, tidak ada disiplin skema atau pelacakan lintas lompatan, dan pesan gagal lenyap diam-diam.
- Tingkat 2, Mengembangkan: Broker atau log dipakai nyata untuk beberapa alur, dan beberapa tim punya praktik dasar: konsumen mulai idempoten dan dead letter queue menangkap sebagian kegagalan. Tetapi pendekatan tidak konsisten lintas tim, peristiwa dan perintah masih kacau, skema berubah lewat kesepakatan informal, dan observabilitas tipis.
- Tingkat 3, Membakukan: Peristiwa, perintah, dan pesan dibedakan dengan sengaja di seluruh organisasi. Konsumen idempoten sebagai standar, skema hidup dalam registri dengan kebijakan kompatibilitas terdokumentasi dan ditegakkan, dan transactional outbox menjamin pengiriman. Saga dengan kompensasi menangani transaksi multilayanan, ID korelasi merambat melalui setiap lompatan, dan pola ini dituliskan serta diterapkan konsisten alih-alih diserahkan pada setiap tim.
- Tingkat 4, Mengelola: Platform peristiwa diukur dan dikendalikan dengan data terhadap garis dasar. Lag konsumen, kedalaman dead letter queue, tingkat pengiriman ulang, dan latensi pemrosesan dilacak sebagai metrik peringatan dengan ambang yang disepakati, bukan dasbor yang tak ditonton; kompatibilitas skema diverifikasi otomatis sebelum produsen dapat mengirim perubahan; pemutaran ulang, penanganan kegagalan, dan idempotensi diuji pada irama tetap alih-alih diharapkan. Apakah interaksi tertentu harus peristiwa atau panggilan sinkron diputuskan atas bukti, dan kapasitas, biaya retensi, dan keandalan setiap broker ditinjau terhadap target.
- Tingkat 5, Mengorkestrasi: Gaya berbasis peristiwa dan sinkron dipilih per interaksi sebagai hal yang wajar, dan event sourcing serta CQRS diterapkan tepat di tempat kebutuhan audit dan kueri membenarkannya dan tidak di tempat lain. Alur asinkron sama dapat diobservasinya dengan yang sinkron, platform terus membaik seiring kebutuhan bergeser (memensiunkan topik mati, mengembangkan tata kelola skema, menyeimbangkan ulang partisi), dan pesan terintegrasi dengan arsitektur yang lebih luas dan strategi audit sehingga organisasi menyesuaikan desain peristiwanya seiring bisnis dan kewajibannya berubah.
Gagasan untuk didiskusikan
- “Peristiwa” Anda saat ini yang mana yang diam-diam perintah, dan kopling apa yang akan Anda hapus dengan memodelkannya secara jujur?
- Jika Anda memutar ulang sehari penuh peristiwa melalui konsumen Anda besok, apa yang akan rusak, dan apa yang dikatakan itu tentang idempotensi dan keamanan-pemutaran-ulang Anda?
- Bagian domain Anda yang mana yang benar-benar membutuhkan jejak audit event sourcing, dan mana yang status sederhana yang hanya akan Anda rumitkan dengan sourcing?
- Bagaimana Anda akan bermigrasi dari enterprise service bus warisan atau jaring integrasi titik-ke-titik tanpa cutover big-bang yang berisiko?
- Untuk proses multilayanan terpenting Anda, apakah ia saga terorkestrasi sungguhan dengan kompensasi, atau koreografi emergen yang tak dijelaskan satu tempat pun?
Poin-poin utama
- Arsitektur berbasis peristiwa membeli pemisahan, penskalaan independen, pemutaran ulang, dan jejak audit, dan memakan keterpahaman serta kompleksitas operasional, jadi pilih per interaksi di tempat manfaatnya nyata.
- Jaga peristiwa (fakta yang terjadi), perintah (permintaan bertindak), dan pesan (amplop) tetap berbeda, karena kebingungannya menyebabkan kesalahan kopling nyata.
- Rancang untuk pengiriman setidaknya-sekali dan jadikan setiap konsumen idempoten; pengiriman tepat-sekali adalah mitos, dan efek tepat-sekali adalah pencapaian rekayasa.
- Urutan per partisi, skema adalah kontrak yang termasuk dalam registri, dan outbox, dead letter queue, serta backpressure adalah perpipaan yang membuat pesan siap produksi.
- Gunakan saga dengan kompensasi alih-alih two-phase commit, dan raih event sourcing serta CQRS hanya di tempat kebutuhan audit dan kueri membenarkan biaya curamnya.
- Alur asinkron senyap ketika gagal, jadi ID korelasi, pemantauan lag konsumen, dan pelacakan ujung ke ujung adalah beda antara sistem yang dapat dioperasikan dan yang tak terlihat.
Referensi dan bacaan lanjutan
- Martin Kleppmann, Designing Data-Intensive Applications
- Gregor Hohpe dan Bobby Woolf, Enterprise Integration Patterns
- Chris Richardson, Microservices Patterns (saga, transactional outbox, CQRS)
- Sam Newman, Building Microservices
- Ben Stopford, Designing Event-Driven Systems
- Adam Bellemare, Building Event-Driven Microservices
- Vaughn Vernon, Implementing Domain-Driven Design (event sourcing dan CQRS)
- Martin Fowler, “Event Sourcing” dan “CQRS” (artikel martinfowler.com)
- Hector Garcia-Molina dan Kenneth Salem, “Sagas” (1987)