Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Rancang konsumen pesan sehingga pemrosesan pesan yang sama lebih dari satu kali menimbulkan dampak yang sama seperti saat diproses satu kali. Sistem olahpesan yang menjamin pengiriman setidaknya sekali dapat mengirimkan pesan yang sama beberapa kali. Ketahanan terhadap duplikat memastikan bahwa pemrosesan ulang pesan tidak membuat rekaman duplikat, menagih ganda pelanggan, atau memiliki efek lain yang tidak diinginkan.
Konteks dan masalah
Aplikasi terdistribusi biasanya bekerja melalui broker pesan alih-alih menggunakan panggilan sinkron langsung. Sebagian besar broker, termasuk Azure Service Bus, Azure Event Hubs, Apache Kafka, dan RabbitMQ, menyediakan pengiriman setidaknya sekali. Jaminan ini memastikan bahwa pesan mencapai konsumen bahkan ketika kegagalan terjadi, tetapi juga berarti bahwa broker dapat mengirimkan pesan yang sama lebih dari sekali.
Tidak praktis untuk menjamin pengiriman tepat sekali di seluruh sistem terdistribusi. Bahkan broker yang menggunakan semantik persis sekali hanya dapat menjamin operasi yang mereka kontrol langsung, seperti mengirimkan pesan kepada konsumen atau menulis data kembali ke broker. Mereka tidak dapat mengontrol efek samping yang diterapkan konsumen dalam sistem eksternal. Solusi tahan lama bukan untuk menghilangkan pengiriman duplikat tetapi untuk membuat konsumen memprosesnya dengan benar. Ketika Anda menggabungkan pengiriman setidaknya satu kali dengan konsumen yang mengabaikan duplikat, Anda mencapai pemrosesan yang secara efektif hanya terjadi sekali.
Duplikat dapat muncul dari beberapa sumber:
Produsen mencoba lagi. Produsen mengirim pesan, tidak menerima konfirmasi karena gangguan jaringan sementara atau batas waktu terlampaui, lalu mengirim pesan itu lagi. Broker sekarang menyimpan dua salinan meskipun pengiriman berhasil pertama kali.
Pengiriman ulang setelah konfirmasi tidak diterima. Konsumen menerima dan memproses pesan, tetapi gagal mengirimkan konfirmasi penerimaan karena mengalami kegagalan, kunci kedaluwarsa, atau konfirmasi penerimaan hilang. Broker mengasumsikan pesan tidak diproses dan mengirimkannya lagi.
Kegagalan konsumen saat pemrosesan. Seorang konsumen menyelesaikan penulisan ke database tetapi mengalami kegagalan sebelum memberikan konfirmasi penerimaan pesan tersebut. Instance lain mengambil pesan tersebut dan mengulangi operasi penulisan.
Solusi
Buat konsumen idempoten dengan membuat konsumen menyimpan catatan pesan yang berhasil diprosesnya dan mengabaikan pesan apa pun yang sudah diproses, berdasarkan pengenal stabil yang tetap sama saat pesan dikirim ulang. Konsumen memeriksa penyimpanan pengidentifikasi persisten untuk menentukan apakah sudah memproses pengidentifikasi tersebut, lalu memproses pesan atau membuangnya sebagai duplikat.
Alur inti terdiri dari langkah-langkah berikut:
- Baca pesan dan ekstrak kunci deduplikasinya.
- Periksa penyimpanan deduplikasi untuk kunci tersebut.
- Jika kunci sudah ada di penyimpanan, perlakukan pesan sebagai duplikat. Mengakui pesan dan berhenti memprosesnya, secara opsional mengembalikan hasil yang direkam sebelumnya.
- Jika kunci belum ada di penyimpanan, proses pesan dan rekam kunci dalam satu operasi atomik, lalu akui pesan tersebut.
Bagian-bagian berikut memberikan panduan untuk membuat konsumen idempoten:
Pilih kunci deduplikasi yang stabil
Kunci deduplikasi harus dapat mengidentifikasi pesan logis yang sama secara unik dan konsisten pada setiap pengiriman ulang. Gunakan pengidentifikasi pesan yang ditetapkan produsen atau kunci idempotensi tingkat bisnis yang mengidentifikasi operasi logis tertentu, bukan konteks korelasi bersama yang dapat dibawa oleh beberapa pesan.
Misalnya, atur properti Bus Layanan MessageId ke nilai yang secara unik mengidentifikasi pesan logis. Jangan gunakan CorrelationId sebagai kunci, karena mengacu pada grup pesan terkait, seperti permintaan dan balasannya. Untuk event yang mengikuti spesifikasi CloudEvents, kombinasi atribut source dan id secara unik mengidentifikasi sebuah event dan tetap sama di seluruh pengiriman ulang.
Jangan bergantung pada pengidentifikasi level transport yang dibuat ulang oleh broker saat pengiriman ulang, atau pada nilai yang diturunkan dari percobaan pengiriman. Nilai-nilai tersebut berubah di setiap pengiriman dan menyebabkan deteksi duplikat gagal. Hindari juga menurunkan kunci dari kolom yang volatil, seperti stempel waktu penerimaan.
Ketika lebih dari satu konsumen independen memproses saluran yang sama, seperti beberapa pelanggan dalam pola publikasi-berlangganan, setiap konsumen menerima salinan pesan masing-masing dan perlu secara mandiri melacak penyelesaian pemrosesannya. Jika konsumen berbagi penyimpanan deduplikasi, gunakan gabungan identitas konsumen dan identitas pesan sebagai kunci untuk rekaman. Penyimpanan data yang hanya menggunakan identitas pesan sebagai kunci akan memungkinkan konsumen pertama mencegah pemrosesan oleh semua konsumen lainnya.
Memutuskan tempat menyimpan kunci yang diproses
Opsi penyimpanan berikut umum untuk kunci yang diproses:
Tabel deduplikasi khusus. Konsumen mempertahankan tabel terpisah, kadang-kadang disebut kotak masuk, yang menyimpan satu baris per kunci yang diproses. Pendekatan ini membuat masalah deduplikasi terpisah dari data bisnis dan berfungsi dengan baik jika banyak jenis pesan memiliki mekanisme yang sama.
Entitas bisnis itu sendiri. Konsumen menyimpan kunci pada catatan yang dibuat atau diperbarui oleh pesan. Pendekatan ini menghindari penggunaan tabel terpisah, tetapi mengaitkan deduplikasi dengan jenis data bisnis.
Catat kunci yang telah diproses dan efek samping secara atomik
Alur pemeriksaan kemudian proses memiliki jendela kegagalan. Jika konsumen memproses pesan lalu mencatat kuncinya dalam langkah terpisah, jika terjadi kegagalan sistem di antara kedua operasi tersebut, efek samping sudah terlanjur diterapkan tetapi kuncinya belum tercatat, sehingga konsumen akan memproses ulang pesan pada pengiriman ulang berikutnya.
Hindari celah kegagalan ini dengan menulis penanda deduplikasi dan efek samping bisnis dalam transaksi yang sama. Jika konsumen melakukan kedua operasi tersebut secara bersamaan atau tidak melakukannya sama sekali, saat pesan dikirim ulang, konsumen akan menemukan penanda lalu melewati pesan tersebut, atau tidak menemukan penanda karena transaksi tidak berhasil diselesaikan dan memproses ulang pesan tersebut dengan aman. Varian transaksional ini adalah pola Inbox, dan merupakan pendamping di sisi konsumen untuk pola Transactional Outbox di sisi produsen.
Menjaga dari duplikat bersamaan
Dalam pengiriman minimal satu kali dengan konsumen konkuren, dua instans dapat menerima salinan pesan yang sama pada saat yang sama. Kedua instans dapat melewati pengecekan keberadaan sebelum salah satu instans melakukan commit, sehingga pengecekan saja tidak mencegah pemrosesan ganda.
Berlakukan kebenaran di penyimpanan data alih-alih dalam logika aplikasi dengan mengambil langkah-langkah berikut:
Gunakan batasan keunikan pada kunci deduplikasi sehingga dua transaksi dapat mencoba memasukkan kunci, tetapi hanya satu yang dapat berhasil. Transaksi lain gagal membatasi dan memperlakukan pesan sebagai duplikat. Pendekatan ini menjadikan database sebagai arbiter tunggal konflik.
Hindari kondisi balapan check-then-set pada cache. Pola yang memeriksa kunci lalu mengaturnya dalam dua operasi terpisah memiliki jendela yang memungkinkan percobaan ulang bersamaan mengklaim kunci. Gunakan operasi tulis kondisional atomik, seperti penyisipan yang gagal jika terjadi konflik atau operasi tetapkan-jika-belum-ada, agar proses mengklaim kunci menjadi satu langkah atomik.
Menangani efek samping yang tidak dapat bergabung dengan transaksi
Beberapa proses tidak dapat berpartisipasi dalam transaksi database konsumen, seperti memanggil API pihak ketiga atau menulis ke penyimpanan eksternal. Gunakan pendekatan dua fase berikut untuk proses ini:
- Catat kunci dengan status dalam proses, lalu lakukan tindakan eksternal.
- Perbarui catatan untuk diselesaikan dan simpan hasilnya.
Pada pengiriman ulang, catatan selesai memberi tahu konsumen agar tidak mengulangi pemanggilan tersebut. Rekaman yang sedang berlangsung menandakan bahwa upaya sebelumnya mungkin diselesaikan sebagian atau sedang diproses oleh konsumen lain. Penerima harus merekonsiliasi rekaman yang usang atau meneruskan kasus yang belum terselesaikan untuk intervensi sebelum mengakui pengiriman ulang.
Masalah dan pertimbangan
Pertimbangkan poin-poin berikut saat Anda memutuskan cara menerapkan pola ini:
Utamakan operasi yang secara alami bersifat idempoten. Beberapa operasi pada dasarnya bersifat idempoten dan tidak memerlukan pencatatan deduplikasi. Upsert yang menggunakan pengidentifikasi bisnis sebagai kunci, operasi tulis yang menetapkan nilai absolut alih-alih inkremen, atau permintaan HTTP
PUTke pengidentifikasi sumber daya menghasilkan hasil yang sama baik dijalankan sekali maupun berkali-kali.Anda terkadang dapat membuat operasi secara alami menjadi idempoten dengan menggunakan transfer status yang dibawa oleh kejadian. Pesan tersebut membawa keadaan absolut yang dihasilkan, misalnya status baru sebuah pesanan, sehingga konsumen memprosesnya sebagai upsert, bukan sebagai perubahan relatif.
Tip
Rancang agar secara alami idempoten jika memungkinkan, dan gunakan teknik deduplikasi hanya untuk operasi yang tidak dapat dibuat idempoten secara alami.
Gunakan kerangka kerja olahpesan alih-alih mengonfigurasi deduplikasi. Mengimplementasikan penyimpanan deduplikasi, commit, dan pembersihan dengan benar rawan kesalahan. Kerangka kerja berbasis pesan menyediakan pola ini sebagai fitur bawaan.
Misalnya, NServiceBus menghapus duplikasi pesan masuk berdasarkan pengidentifikasi pesannya dan menyediakan masa penyimpanan serta pembersihan yang dapat dikonfigurasi untuk data deduplikasi. Kotak keluar konsumen MassTransit melacak pesan yang diterima oleh pengidentifikasi pesan mereka untuk memberikan perilaku konsumen tepat sekali.
Mengelola siklus hidup rekaman deduplikasi. Rekaman deduplikasi akan terus bertambah kecuali jika Anda mengatur agar kedaluwarsa. Pertahankan setiap catatan setidaknya selama broker masih dapat mengirim ulang pesan asli. Ukuran jendela ini tergantung pada jumlah maksimum upaya pengiriman oleh broker, durasi penguncian atau batas waktu visibilitas, dan masa berlaku pesan.
Atur masa aktif pada catatan deduplikasi agar lebih lama daripada jendela ini, sehingga pengiriman ulang yang terlambat tetap dapat menemukan penandanya. Menghapus rekaman terlalu dini membuka kembali jendela untuk duplikat. Perhitungkan pesan yang dikirim ulang oleh operator dari antrean dead-letter, karena pengiriman ulang ini dapat terjadi lama setelah periode pengiriman ulang normal berakhir.
Jangan menggantikan logika konsumen idempoten dengan deduplikasi broker. Beberapa platform menyaring duplikat pada lapisan transportasi. Misalnya, deteksi duplikat Bus Layanan membuang pesan yang mengulangi
MessageIddalam jangka waktu yang dikonfigurasi, yang mencegah percobaan ulang pengiriman duplikat oleh produsen.Fitur ini beroperasi di sisi pengiriman dan dalam rentang terbatas, sehingga tidak mencegah konsumen memproses pesan yang sama dua kali setelah pengiriman ulang. Anda masih memerlukan logika konsumen yang idempoten. Gunakan fitur platform untuk mengurangi jumlah duplikasi, bukan sebagai pengganti pola Idempotent Consumer.
Perhitungkan urutan pesan. Deduplikasi menghapus duplikat, tetapi tidak menjamin urutan. Jika konsumen bergantung pada pesanan pemrosesan, gabungkan pola ini dengan mekanisme pemesanan seperti Bus Layanan sesi pesan, atau sertakan urutan atau data versi sehingga konsumen dapat menolak pesan kedaluarsa.
Instrumen untuk pengamatan. Keluarkan kunci deduplikasi dan pengidentifikasi korelasi dalam log terstruktur, dan lacak metrik untuk duplikat yang terdeteksi. Tingkat duplikat yang meningkat dapat menunjukkan kesalahan konfigurasi produsen, pengakuan berukuran kecil atau jendela kunci, atau konsumen yang tidak sehat. Gunakan pelacakan dan korelasi terdistribusi untuk mengikuti pesan di seluruh layanan.
Menyebarkan idempotensi ke panggilan hilir. Menjadikan konsumen pesan bersifat idempoten tidak melindungi layanan yang dipanggilnya. Saat konsumen memanggil layanan hilir sebagai bagian dari pemrosesan, teruskan kunci idempoten agar setiap lapisan layanan dapat menghilangkan duplikasi pekerjaannya sendiri.
Kapan menggunakan pola ini
Gunakan pola ini ketika:
Anda menerima pesan dari broker yang menyediakan jaminan pengiriman setidaknya satu kali, yang merupakan opsi bawaan untuk sebagian besar broker.
Pemrosesan ulang pesan dapat menghasilkan hasil yang salah, seperti transaksi keuangan duplikat, pembuatan sumber daya duplikat, atau pemberitahuan berulang.
Beberapa konsumen yang bersaing memproses saluran yang sama, yang membuat pengiriman duplikat bersamaan lebih mungkin.
Pola ini mungkin tidak cocok ketika:
Operasi yang dilakukan konsumen secara alami sudah bersifat idempoten, sehingga pemrosesan ulang tidak menimbulkan masalah dan pencatatan deduplikasi hanya menambah biaya tanpa manfaat.
Beban kerja dapat mentoleransi dampak dari pemrosesan duplikat yang sesekali terjadi, dan biaya penyimpanan deduplikasi lebih besar daripada dampak duplikasi.
Pemrosesan idempotensi di luar olahpesan
Pola ini menerapkan prinsip idempoten pada konsumen pesan, tetapi pemrosesan idempoten merupakan prinsip keandalan yang lebih luas yang dapat bermanfaat bagi operasi apa pun yang dijalankan lebih dari sekali pada tugas yang identik. Prinsip ini mencakup transformasi extract, transform, load (ETL) yang memproses ulang data yang diputar ulang, pemrosesan aliran yang dilanjutkan dari titik pemeriksaan, pekerjaan terjadwal yang tumpang tindih atau dimulai ulang, serta titik akhir webhook atau HTTP yang menerima pengiriman duplikat.
Teknik inti yang sama berlaku di setiap kasus.
- Gunakan kunci stabil untuk mengidentifikasi unit kerja.
- Rekam apa yang Anda proses.
- Lewati atau gabungkan eksekusi ganda agar pengulangan pekerjaan tidak mengubah hasilnya.
Mekanisme dalam artikel ini, seperti kunci stabil, penanda atom, dan batasan keunikan, mentransfer ke konteks ini bahkan ketika tidak ada broker pesan yang terlibat.
Desain beban kerja
Evaluasikan cara menggunakan pola Idempotent Consumer dalam desain beban kerja untuk memenuhi tujuan dan prinsip yang tercakup dalam pilar Azure Well-Architected Framework. Tabel berikut memberikan panduan tentang bagaimana pola ini mendukung tujuan setiap pilar.
| Prinsip Dasar | Bagaimana pola ini mendukung tujuan pilar |
|---|---|
| Keputusan desain Keandalan membantu beban kerja Anda menjadi tangguh tidak berfungsi dan memastikan bahwa memulihkan ke keadaan yang berfungsi penuh setelah kegagalan terjadi. | Pola ini memungkinkan beban kerja menggunakan pengiriman setidaknya sekali dan percobaan ulang yang aman tanpa merusak data, yang mengubah pengiriman duplikat dari risiko kebenaran menjadi kondisi yang ditoleransi. - RE:07 Perlindungan Diri Kesalahan sementara - |
Jika pola ini memperkenalkan kompromi di dalam pilar, bandingkan dengan tujuan pilar lain.
Example
Contoh berikut menjelaskan konsumen idempoten yang memproses pesanan dari Bus Layanan dan menyimpan status dalam Azure Cosmos DB for NoSQL.
- Produsen menetapkan Bus Layanan
MessageIdsebagai pengenal pesanan tingkat bisnis. - Konsumen menerima pesan dalam mode PeekLock, yang membuat pesan tersedia untuk pengiriman ulang jika konsumen tidak menyelesaikan pesan tersebut sebelum masa berlaku kunci berakhir.
- Kontainer Azure Cosmos DB konsumen dipartisi berdasarkan pengidentifikasi pesanan
/orderIddan menetapkaniddokumen ke pengidentifikasi pesanan yang sama, sehingga setiap salinan dari pesanan tertentu dipetakan ke partisi logis yang sama dan pesananiditu sendiri berfungsi sebagai penanda deduplikasi.
Konsumen mengambil langkah-langkah berikut untuk memproses setiap pesan:
- Baca pesan dan gunakan
MessageIdsebagai kunci deduplikasi. - Coba buat dokumen pesanan dengan
iddan kunci partisi, keduanya diatur ke ID pesanan. - Jika pembuatan berhasil, tandai pesan sebagai selesai agar Bus Layanan menghapusnya dari antrean.
- Jika proses pembuatan gagal dengan status HTTP 409 (Konflik) karena dokumen dengan
idtersebut sudah ada, baca dokumen yang sudah ada dan bandingkan dengan pesan saat ini. - Jika hash permintaan yang tersimpan atau kolom bisnis yang tidak dapat diubah cocok, perlakukan pesan tersebut sebagai duplikat, tandai sebagai selesai, dan lewati pemrosesan lebih lanjut.
- Jika hash permintaan yang tersimpan atau kolom bisnis yang tidak boleh diubah tidak cocok, kirim pesan ke dead-letter queue dan picu peringatan, alih-alih mengabaikan pesan begitu saja. Produsen mungkin telah menggunakan kembali pengidentifikasi untuk konten yang berbeda, atau detail pesan mungkin telah berubah sejak pesanan pertama kali diproses.
- Jika pemrosesan gagal karena penyebab sementara, lepaskan pesan agar Bus Layanan mengirimkannya kembali, atau biarkan kunci kedaluwarsa agar konsumen lain dapat menerimanya.
Operasi pembuatan bersifat atomik, sehingga berfungsi sekaligus sebagai pemeriksaan deduplikasi dan operasi penulisan. Dua konsumen yang menerima salinan pesan yang sama tidak dapat membuat pesanan keduanya. Salah satu upaya pembuatan berhasil, dan upaya lainnya menghasilkan konflik serta membuang duplikatnya dengan aman.
Saat memproses harus menulis lebih dari satu dokumen, gunakan batch transaksional yang menyertakan kunci deduplikasi dan dokumen bisnis dalam kunci partisi yang sama. Karena batch transaksional beroperasi dalam satu partisi logis, Anda memilih kunci partisi yang digunakan bersama oleh semua dokumen untuk satu pesan. Batch meng-commit semua dokumen sekaligus atau tidak ada satu pun yang di-commit, sehingga kegagalan sistem di antara pemrosesan dan konfirmasi tidak akan menyebabkan penanda deduplikasi dan data bisnis menjadi tidak sinkron. Batch yang mencoba membuat dokumen yang sudah ada akan mengembalikan status 409 (Konflik), yang menandakan adanya duplikat.
Untuk membuat konsumen idempoten ini juga tangguh terhadap percobaan kirim ulang duplikat, aktifkan deteksi duplikat pada antrean. Pada antrean Standar atau Premium, deteksi duplikat mencegah pengiriman yang berulang dalam jendela riwayatnya. Konsumen idempoten masih menangani duplikasi apa pun yang berada di luar jendela tersebut atau yang dihasilkan dari pengiriman ulang.
Langkah selanjutnya
- Merancang Azure Functions untuk input yang identik memberikan panduan untuk membangun fungsi idempotensi yang mentolerir pemanggilan duplikat.
Sumber daya terkait
Opsi olahpesan asinkron di Azure menjelaskan pilihan infrastruktur olahpesan yang menentukan jaminan pengiriman dan persyaratan penanganan duplikat Anda.
Pola Transactional Outbox, yang secara andal menerbitkan pesan dengan mengkomit pesan-pesan tersebut dalam transaksi yang sama dengan data bisnis, adalah sisi penerbit dari pola Konsumen Idempoten.
Pola Coba Lagi memungkinkan aplikasi menangani kesalahan sementara dengan mencoba kembali operasi, yang membuat pemrosesan idempogen diperlukan karena percobaan ulang dapat menyebabkan pengiriman duplikat.
Desain Azure Event Hubs dan Azure Functions yang andal menerapkan pola ini pada fungsi yang dipicu oleh Event Hubs, termasuk teknik deduplikasi untuk stream peristiwa.