Kodeloka
  1. Kodeloka
  2. Kelas Redis
  3. Materi

Advanced ยท Modul 13 dari 21

Consumer Group - Pemrosesan Andal & At-Least-Once

Membagi beban pemrosesan stream ke banyak worker dengan jaminan setiap pesan diproses, memakai XREADGROUP, XACK, XPENDING, dan XAUTOCLAIM.

๐Ÿ“Œ Ringkasan Eksekutif Modul:
Consumer Group memungkinkan beberapa worker membagi entri dari satu Stream tanpa tumpang tindih, sambil melacak entri mana yang sudah dikonfirmasi selesai. Entri yang sudah dikirim tapi belum di-XACK masuk ke daftar PEL (Pending Entries List). Bila worker mati, entri tersebut bisa diambil alih worker lain lewat XAUTOCLAIM. Model jaminannya at-least-once, sehingga consumer WAJIB idempoten.

1. Tiga Peran yang Perlu Dibedakan

  • Stream โ€” lognya sendiri, misal pesanan.
  • Consumer Group โ€” sekelompok worker yang bersama-sama menghabiskan satu stream. Group menyimpan posisi baca terakhir di sisi server, bukan di aplikasi.
  • Consumer โ€” anggota individual di dalam group, punya nama sendiri (misal worker-1).
๐Ÿ’ก Kunci pemahamannya: Beberapa group berbeda yang membaca satu stream sama akan sama-sama menerima semua pesan (seperti broadcast). Tetapi beberapa consumer di dalam satu group akan membagi pesan (seperti antrian kerja). Jadi satu stream bisa sekaligus melayani pola pub/sub dan pola work-queue.

2. Membuat Group

redis-cli
# Buat group yang mulai membaca dari entri PALING AWAL
XGROUP CREATE pesanan grup-notifikasi 0

# Buat group yang hanya membaca entri BARU (setelah perintah ini)
XGROUP CREATE pesanan grup-analitik $

# MKSTREAM: buat stream-nya sekalian bila belum ada.
# Tanpa ini, perintah gagal kalau stream belum pernah ditulisi.
XGROUP CREATE pesanan grup-invoice 0 MKSTREAM

# Lihat semua group pada satu stream
XINFO GROUPS pesanan

3. Membaca sebagai Anggota Group: XREADGROUP

# Tanda > berarti "beri saya entri yang BELUM PERNAH dikirim
# ke consumer mana pun di group ini"
XREADGROUP GROUP grup-notifikasi worker-1 COUNT 10 BLOCK 5000 STREAMS pesanan >

# ID 0 berarti "beri saya entri yang SUDAH dikirim ke SAYA
# tapi belum saya konfirmasi" -- dipakai saat worker baru restart
XREADGROUP GROUP grup-notifikasi worker-1 COUNT 10 STREAMS pesanan 0
๐Ÿ“Œ Pola startup worker yang benar

Saat worker menyala, jangan langsung membaca >. Baca dulu dengan ID 0 untuk menghabiskan pekerjaan yang tertinggal dari sesi sebelumnya, baru beralih ke > setelah daftarnya kosong. Melewatkan langkah ini membuat pesan menggantung di PEL tanpa ada yang mengerjakannya.

4. PEL: Pending Entries List

Begitu sebuah entri dikirim ke consumer lewat XREADGROUP, Redis mencatatnya di PEL โ€” daftar "sedang dikerjakan, belum dikonfirmasi". Entri keluar dari PEL hanya ketika di-XACK.

# Ringkasan: berapa banyak yang menggantung, ID terkecil & terbesar, per consumer
XPENDING pesanan grup-notifikasi

# Rincian 10 entri menggantung, lengkap dengan
# berapa lama menggantung (idle time, ms) dan berapa kali dikirim ulang
XPENDING pesanan grup-notifikasi - + 10

# Hanya milik worker tertentu
XPENDING pesanan grup-notifikasi - + 10 worker-1

# Konfirmasi selesai -- entri dibuang dari PEL
XACK pesanan grup-notifikasi 1712345678901-0

5. Worker Mati: Mengambil Alih dengan XAUTOCLAIM

Kalau worker-1 mati setelah menerima entri tapi sebelum XACK, entri itu terjebak di PEL milik worker-1 selamanya. Worker lain harus mengambil alih.

# Ambil alih entri yang sudah menganggur lebih dari 60 detik (60000 ms)
# ke consumer bernama worker-2, mulai dari kursor 0-0
XAUTOCLAIM pesanan grup-notifikasi worker-2 60000 0-0 COUNT 10

# Hasilnya: [kursor-berikutnya, [entri...], [id-yang-sudah-dihapus...]]
# Panggil berulang dengan kursor yang dikembalikan sampai kursornya 0-0.

# XCLAIM adalah versi manual untuk ID spesifik
XCLAIM pesanan grup-notifikasi worker-2 60000 1712345678901-0
โš ๏ธ Pesan beracun (poison message)

Kalau sebuah entri selalu membuat worker crash, entri itu akan di-claim berulang kali tanpa henti dan memblokir kemajuan group. Periksa kolom delivery count dari XPENDING: bila sudah melewati ambang tertentu (misal 5 kali), pindahkan entri itu ke stream pesanan-dlq lalu XACK aslinya. Ini setara Dead Letter Queue di RabbitMQ, hanya saja di Redis Anda harus membangunnya sendiri.

6. Jaminan Pengiriman: At-Least-Once, Bukan Exactly-Once

Urutan kejadiannya begini:

1. XREADGROUP  -> entri masuk PEL
2. Worker memproses (misal: kirim email)
3. XACK        -> entri keluar dari PEL

Kalau worker mati di antara langkah 2 dan 3, email sudah terkirim tetapi entri belum di-ACK. Worker lain akan mengambil alih dan mengirim email itu lagi.

๐Ÿšซ Tidak ada exactly-once di sistem terdistribusi

Yang bisa Anda capai adalah efek exactly-once melalui idempotensi: simpan ID entri yang sudah selesai diproses (misal di Set Redis atau kolom unik di database), dan lewati bila sudah pernah ada. Cara paling kokoh: jadikan penulisan hasil dan penandaan "sudah diproses" berada dalam satu transaksi database yang sama.

7. Membersihkan Consumer yang Sudah Tidak Dipakai

# Lihat consumer di dalam group beserta idle time-nya
XINFO CONSUMERS pesanan grup-notifikasi

# Hapus consumer yang sudah mati permanen (misal pod lama di Kubernetes).
# PERINGATAN: entri di PEL miliknya ikut hilang -- claim dulu sebelum menghapus!
XGROUP DELCONSUMER pesanan grup-notifikasi worker-lama

# Hapus group seluruhnya
XGROUP DESTROY pesanan grup-analitik

# Geser posisi baca group secara manual (misal untuk replay dari awal)
XGROUP SETID pesanan grup-analitik 0
๐Ÿ“Œ Di Kubernetes, nama consumer sebaiknya stabil

Kalau nama consumer memakai hostname pod yang berubah setiap deploy, PEL akan penuh dengan consumer yatim. Pakai StatefulSet (nama pod stabil: worker-0, worker-1) atau jalankan XAUTOCLAIM secara berkala sebagai jaring pengaman.