Kodeloka
  1. Kodeloka
  2. Kelas Apache Kafka
  3. Materi

2 · Produksi & Konsumsi · Modul 5 dari 13

Consumer Group, Rebalancing & Commit Offset

Sebagian besar insiden Kafka di produksi berakar di sisi konsumen: rebalance yang tak berhenti, offset yang salah di-commit, dan pesan yang diproses dua kali.

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
⚠️ Menambah pod tidak selalu menambah kapasitas

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.

StrategiPerilaku
RangeAssignorWarisan; pembagian sering tidak merata
CooperativeStickyAssignorHanya 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
💡 Pakai cooperative sticky

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.

SetelanDefaultFungsi
max.poll.interval.ms5 menitBatas waktu antar panggilan poll — melampaui ini berarti dikeluarkan dari grup
max.poll.records500Jumlah pesan maksimum per poll
session.timeout.ms45 detikBatas waktu heartbeat sebelum dianggap mati
heartbeat.interval.ms3 detikFrekuensi heartbeat
🚫 Pemrosesan lambat memicu rebalance berantai

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
⚠️ enable.auto.commit=true menyembunyikan masalah

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.

💡 At-least-once adalah default yang sehat

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
⚠️ Salah ketik group.id berarti mulai dari nol

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.