Kodeloka
  1. Kodeloka
  2. Kelas RabbitMQ
  3. Materi

Modul 6 · Modul 6 dari 15

Durability, Persistence, dan Publisher Confirms

Menutup setiap celah kehilangan pesan dari producer sampai disk, dan mengetahui harga yang dibayar untuk setiap jaminan.

Empat Titik Kehilangan Pesan

peta kehilangantext
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 idempoten

Menutup satu titik saja tidak cukup. Sistem yang benar-benar tidak kehilangan pesan menutup keempatnya secara sadar.

Durable ≠ Persistent

durablepersistent
Milik siapaQueue dan exchangePesan
ArtinyaDefinisinya bertahan saat restartIsinya ditulis ke disk
Diset di manaSaat deklarasi queueSaat publish (delivery_mode=2)
kombinasitext
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.

tiga cara menunggu confirmjavascript
// 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.
⛔ Jangan pakai transaksi AMQP

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?

perbandingan kasartext
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)
💡 Tidak semua pesan berhak atas jaminan yang sama

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

policy batas queuebash
rabbitmqctl set_policy batas-antrean "^pesanan\." \
  '{"max-length":100000,
    "max-length-bytes":1073741824,
    "overflow":"reject-publish",
    "message-ttl":86400000}' \
  --apply-to queues
overflowPerilaku saat penuhPakai untuk
drop-headBuang pesan tertuaData yang basi tidak berguna, mis. posisi terkini
reject-publishTolak publish baru, producer dapat errorPekerjaan yang tidak boleh hilang
reject-publish-dlxTolak, dan kirim ke DLXIngin menyimpan yang tertolak
⚠️ Queue tanpa batas adalah bom waktu

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.

policy vs argumenbash
rabbitmqctl set_policy ha-pesanan "^pesanan\." \
  '{"max-length":100000,"message-ttl":3600000}' \
  --priority 10 --apply-to queues

rabbitmqctl list_policies
rabbitmqctl clear_policy ha-pesanan

Aturan 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).