Empat Titik Kehilangan Pesan
Producer ──①──> Broker ──②──> Queue ──③──> Disk
│
④
▼
Consumer
① Publish gagal / broker mati sebelum menerima
→ obat: publisher confirms
② Tidak ada binding cocok, pesan dibuang diam-diam
→ obat: mandatory + basic.return, atau alternate-exchange
③ Broker restart, queue atau pesan tidak ada di disk
→ obat: queue durable + delivery_mode 2
④ Konsumer mati setelah ack tetapi sebelum menyelesaikan pekerjaan
→ obat: ack SETELAH selesai + konsumer idempotenMenutup satu titik saja tidak cukup. Sistem yang benar-benar tidak kehilangan pesan menutup keempatnya secara sadar.
Durable ≠ Persistent
durable | persistent | |
|---|---|---|
| Milik siapa | Queue dan exchange | Pesan |
| Artinya | Definisinya bertahan saat restart | Isinya ditulis ke disk |
| Diset di mana | Saat deklarasi queue | Saat publish (delivery_mode=2) |
queue durable=false + pesan persistent=true
→ queue lenyap saat restart; pesannya ikut lenyap. Sia-sia.
queue durable=true + pesan persistent=false
→ queue kembali setelah restart, tetapi KOSONG.
queue durable=true + pesan persistent=true
→ satu-satunya kombinasi yang bertahan. ✅Publisher Confirms
Tanpa konfirmasi, publish() hanyalah menulis ke soket. Ia berhasil walaupun broker mati sepersekian detik kemudian.
// 1. Per pesan — paling sederhana, paling lambat (± 1.000 pesan/detik)
await new Promise((res, rej) => {
ch.publish(ex, rk, body, opsi, (err) => err ? rej(err) : res());
});
// 2. Batch — kompromi yang baik
const batch = [];
for (const item of daftar) {
batch.push(new Promise((res, rej) =>
ch.publish(ex, rk, enc(item), opsi, (e) => e ? rej(e) : res())));
if (batch.length >= 100) { await Promise.all(batch); batch.length = 0; }
}
await Promise.all(batch);
// 3. Asinkron penuh — paling cepat, paling rumit
// Simpan pesan di buffer, hapus saat confirm tiba,
// kirim ulang yang belum terkonfirmasi setelah timeout.
// Wajib menangani nack DAN return sekaligus.tx.select / tx.commit memang ada dalam spesifikasi AMQP, tetapi membuat throughput anjlok hingga seratus kali lipat karena setiap commit memaksa fsync sinkron.
Publisher confirms memberi jaminan yang setara untuk kebutuhan praktis dengan biaya yang jauh lebih kecil. Transaksi AMQP praktis tidak pernah menjadi jawaban yang benar.
Berapa Harga Persistence?
Pesan transient, tanpa confirm .......... ± 50.000 pesan/detik
Pesan persistent, tanpa confirm ......... ± 20.000 pesan/detik
Pesan persistent + confirm batch(100) ... ± 8.000 pesan/detik
Pesan persistent + confirm per pesan .... ± 1.000 pesan/detik
(angka indikatif pada satu node dengan SSD; ukur di lingkungan Anda)Pisahkan berdasarkan konsekuensi kehilangan:
- Transaksi keuangan, pembuatan pesanan → persistent + confirm per pesan. Kehilangan berarti uang atau kepercayaan.
- Notifikasi, email → persistent + confirm batch. Kehilangan mengganggu tetapi tidak fatal.
- Metrik, telemetri, analitik sampling → transient tanpa confirm. Kehilangan sebagian tidak berarti apa-apa.
Memberi jaminan tertinggi pada semua pesan adalah pemborosan yang membatasi kapasitas sistem Anda.
Lazy Queue dan Perubahan di RabbitMQ 3.12+
Dulu ada mode lazy queue yang memaksa pesan langsung ke disk untuk menghemat memori. Sejak RabbitMQ 3.12, classic queue versi 2 berperilaku efisien secara default dan x-queue-mode=lazy menjadi usang.
Bila Anda menemukan panduan lama yang menganjurkan lazy queue, saran yang setara di versi modern adalah: pakai quorum queue (bab 8), yang memang dirancang menampung antrean panjang tanpa membebani memori.
Batasi Ukuran Queue — Selalu
rabbitmqctl set_policy batas-antrean "^pesanan\." \
'{"max-length":100000,
"max-length-bytes":1073741824,
"overflow":"reject-publish",
"message-ttl":86400000}' \
--apply-to queuesoverflow | Perilaku saat penuh | Pakai untuk |
|---|---|---|
drop-head | Buang pesan tertua | Data yang basi tidak berguna, mis. posisi terkini |
reject-publish | Tolak publish baru, producer dapat error | Pekerjaan yang tidak boleh hilang |
reject-publish-dlx | Tolak, dan kirim ke DLX | Ingin menyimpan yang tertolak |
Queue tanpa max-length dan tanpa TTL akan tumbuh sampai disk habis, lalu memicu alarm disk yang memblokir seluruh publish di broker — termasuk queue lain yang sehat. Satu queue yang terabaikan bisa mematikan seluruh sistem pesan Anda.
Policy: Cara yang Benar Mengatur Queue
Argumen yang ditulis di kode saat deklarasi queue bersifat permanen: mengubahnya memerlukan penghapusan dan pembuatan ulang queue. Policy diterapkan dari luar dan bisa diubah kapan saja tanpa menyentuh kode atau data.
rabbitmqctl set_policy ha-pesanan "^pesanan\." \
'{"max-length":100000,"message-ttl":3600000}' \
--priority 10 --apply-to queues
rabbitmqctl list_policies
rabbitmqctl clear_policy ha-pesananAturan praktis: taruh di argumen kode hanya hal yang menjadi bagian dari kontrak queue (tipe queue, DLX). Taruh di policy semua hal operasional (batas panjang, TTL, jumlah replika).