Cara Kerja Consumer Group
Konsumen yang memakai group.id sama membentuk satu grup. Kafka membagi partisi di antara mereka, dan satu partisi hanya boleh dipegang oleh satu konsumen dalam grup itu.
Topik 6 partisi, grup "layanan-notifikasi": 2 konsumen → masing-masing 3 partisi 6 konsumen → masing-masing 1 partisi ← paralelisme maksimum 8 konsumen → 6 bekerja, 2 MENGANGGUR ← partisi habis
Bila jumlah konsumen sudah sama dengan jumlah partisi, menaikkan replika lagi tidak menambah throughput sedikit pun — pod tambahan hanya duduk menganggur menunggu partisi yang tak akan datang. Skala konsumen dibatasi oleh jumlah partisi, dan menambah partisi punya konsekuensi tersendiri pada urutan kunci.
Rebalance: Saat Keanggotaan Berubah
Rebalance terjadi ketika konsumen bergabung, keluar, dianggap mati, atau saat metadata topik berubah. Selama rebalance model lama (eager), seluruh grup berhenti memproses.
| Strategi | Perilaku |
|---|---|
RangeAssignor | Warisan; pembagian sering tidak merata |
CooperativeStickyAssignor | Hanya partisi yang berpindah yang dilepas — sisanya terus bekerja |
| Protokol grup baru (KIP-848) | Koordinasi dipindahkan ke broker; rebalance jauh lebih ringan dan tanpa jeda global |
Pada klien modern, partition.assignment.strategy=org.apache.kafka.clients.consumer.CooperativeStickyAssignor menghilangkan jeda "stop the world" pada tiap rebalance. Kafka 4.x juga membawa protokol consumer group generasi baru yang memindahkan logika penugasan ke broker — arah yang sama, dilakukan lebih menyeluruh.
Penyebab Rebalance yang Tak Berhenti
Ini pola kegagalan paling umum: konsumen terus-menerus dianggap mati, grup terus rebalance, dan lag naik tanpa henti walau CPU rendah.
| Setelan | Default | Fungsi |
|---|---|---|
max.poll.interval.ms | 5 menit | Batas waktu antar panggilan poll — melampaui ini berarti dikeluarkan dari grup |
max.poll.records | 500 | Jumlah pesan maksimum per poll |
session.timeout.ms | 45 detik | Batas waktu heartbeat sebelum dianggap mati |
heartbeat.interval.ms | 3 detik | Frekuensi heartbeat |
Bila memproses 500 pesan butuh lebih dari max.poll.interval.ms, konsumen dikeluarkan dari grup di tengah pekerjaan. Partisinya dipindahkan, konsumen itu kembali, grup rebalance lagi — dan siklus berulang. Gejalanya khas: lag terus naik padahal konsumen tampak sibuk dan tidak ada galat.
Perbaikannya: turunkan max.poll.records agar tiap batch selesai cepat, naikkan max.poll.interval.ms bila pemrosesan memang lama, atau pindahkan pekerjaan berat ke worker terpisah agar loop poll tetap responsif.
Commit Offset: Sumber Duplikat dan Kehilangan
Offset yang di-commit menandai "sudah saya proses sampai sini". Kesalahan menempatkan commit menghasilkan dua bug klasik:
SALAH — commit sebelum memproses (berpotensi kehilangan pesan) pesan = poll() commit() ← offset maju proses(pesan) ← aplikasi mati di sini → pesan tidak pernah diproses BENAR — commit sesudah memproses (at-least-once) pesan = poll() proses(pesan) commit() ← aplikasi mati sebelum ini → pesan diproses ulang
Auto-commit menyimpan offset secara berkala di latar belakang, tanpa tahu apakah pemrosesan Anda benar-benar selesai. Bila aplikasi mati setelah offset ter-commit tetapi sebelum pemrosesan tuntas, pesan itu hilang secara diam-diam. Untuk pemrosesan yang penting, matikan auto-commit dan commit secara eksplisit setelah pekerjaan selesai.
Commit setelah memproses berarti pesan bisa diproses lebih dari sekali saat terjadi crash. Ini hampir selalu pilihan yang benar, asalkan pemrosesan Anda idempoten — dibahas tuntas pada modul pola produksi.
Membaca dari Mana Saat Grup Baru
auto.offset.reset=latest ← default: hanya pesan baru auto.offset.reset=earliest ← dari awal log yang masih ada auto.offset.reset=none ← lempar galat bila tidak ada offset tersimpan
Karena offset disimpan per group.id, salah ketik satu huruf membuat Kafka menganggapnya grup yang belum pernah ada. Dengan earliest, konsumen akan memproses seluruh riwayat topik — kejutan yang mahal pada topik berukuran terabyte.