Consumer Group #

Ketika kita membangun arsitektur pemrosesan data real-time berskala besar, memproduksi data dengan throughput tinggi ke Apache Kafka hanyalah setengah dari perjuangan. Tantangan sesungguhnya terletak pada bagaimana kita bisa mengonsumsi dan memproses data tersebut dengan kecepatan yang sebanding. Jika produser kita mengirimkan puluhan ribu pesan per detik ke sebuah topik, satu instansi konsumen tunggal yang berjalan pada satu utas (single thread) lambat laun akan mengalami ketertinggalan pembacaan (consumer lag). Di sinilah konsep Consumer Group (Kelompok Konsumen) menjadi pilar utama skalabilitas pembacaan di dalam ekosistem Kafka. Dengan mengelompokkan beberapa instansi konsumen di bawah satu identitas kelompok yang sama (Group ID), Kafka secara otomatis mendistribusikan beban pembacaan partisi dari suatu topik secara dinamis di antara anggota kelompok tersebut. Mekanisme ini tidak hanya memberikan kemampuan skalabilitas horisontal secara instan, tetapi juga menyediakan jaminan toleransi kegagalan (fault tolerance) yang tangguh jika salah satu konsumen mengalami kegagalan sistem.


Konsep Dasar Consumer Group dan Skalabilitas Horisontal #

Di dalam dunia perpesanan tradisional (seperti RabbitMQ atau ActiveMQ), terdapat dikotomi yang jelas antara dua model perpesanan utama: Queueing (Point-to-Point) dan Publish-Subscribe.

  • Queueing Model: Beberapa konsumen membaca dari satu antrean yang sama, tetapi setiap pesan hanya akan diproses oleh tepat satu konsumen. Model ini sangat baik untuk skalabilitas pemrosesan, tetapi tidak mendukung banyak aplikasi independen untuk membaca data yang sama secara bersamaan.
  • Publish-Subscribe Model: Setiap pesan disebarluaskan (broadcast) ke seluruh konsumen yang berlangganan. Model ini memungkinkan banyak aplikasi membaca data yang sama, tetapi setiap instansi aplikasi harus memproses seluruh data, sehingga tidak mendukung skalabilitas pemrosesan horisontal dalam satu kluster aplikasi.

Apache Kafka menyatukan kedua keunggulan model ini melalui abstraksi Consumer Group. Di Kafka, setiap konsumen yang ingin membaca data wajib mendeklarasikan nama kelompoknya menggunakan properti group.id.

flowchart TD
    subgraph Cluster["Kafka Cluster"]
        TopicA["Topic: order-events (4 Partitions)"]
        T0["Partition 0"]
        T1["Partition 1"]
        T2["Partition 2"]
        T3["Partition 3"]
        TopicA --> T0
        TopicA --> T1
        TopicA --> T2
        TopicA --> T3
    end

    subgraph GroupA["Consumer Group: billing-service"]
        C1["Consumer 1"]
        C2["Consumer 2"]
    end

    subgraph GroupB["Consumer Group: inventory-service"]
        C3["Consumer 3"]
    end

    T0 -->|"Read"| C1
    T1 -->|"Read"| C1
    T2 -->|"Read"| C2
    T3 -->|"Read"| C2

    T0 -->|"Broadcast Read"| C3
    T1 -->|"Broadcast Read"| C3
    T2 -->|"Broadcast Read"| C3
    T3 -->|"Broadcast Read"| C3

    style GroupA stroke:#0288d1,stroke-width:2px
    style GroupB stroke:#5d4037,stroke-width:2px
    style Cluster stroke:#333,stroke-width:2px

Melalui visualisasi di atas, kita dapat melihat bagaimana Consumer Group menyelesaikan dua masalah sekaligus:

  1. Skalabilitas dalam Satu Kelompok (billing-service): Beban kerja topik dibagi secara dinamis. Consumer 1 membaca Partisi 0 dan 1, sedangkan Consumer 2 membaca Partisi 2 dan 3. Jika kita menambah konsumen ketiga ke grup ini, pembagian partisi akan disesuaikan kembali secara otomatis.
  2. Kemandirian Antar Aplikasi: Kelompok billing-service dan kelompok inventory-service bertindak sebagai dua konsumen logis yang terisolasi. Keduanya menerima salinan data yang sama dari topik tanpa saling mengganggu offset baca satu sama lain.

Mekanisme Pembagian Partisi (Partition Assignment) #

Aturan paling fundamental dalam manajemen kelompok konsumen Kafka adalah: Satu partisi dari suatu topik hanya boleh dialokasikan ke tepat satu instansi konsumen di dalam satu Consumer Group pada satu waktu.

Aturan ini sangat penting untuk memberikan Jaminan Urutan Pesan (Ordering Guarantee). Jika Kafka mengizinkan dua konsumen di dalam grup yang sama untuk membaca partisi yang sama secara paralel, kita akan kehilangan urutan kronologis pemrosesan pesan karena ketidakpastian penjadwalan CPU pada masing-masing mesin konsumen. Dengan membatasi satu partisi untuk satu konsumen, Kafka memastikan bahwa semua pesan di dalam satu partisi akan diproses secara berurutan sesuai dengan waktu penulisannya.

Aturan pembagian ini melahirkan tiga skenario hubungan rasio antara jumlah partisi dengan jumlah instansi konsumen di dalam satu grup:

Skenario 1: Jumlah Konsumen Kurang dari Jumlah Partisi (Under-provisioned) #

Jika topik memiliki 4 partisi (P0, P1, P2, P3) dan grup kita hanya memiliki 2 konsumen (C1, C2), Kafka akan membagi beban secara merata.

  • Pembagian: C1 akan mendapatkan tanggung jawab membaca P0 dan P1. C2 akan mendapatkan tanggung jawab membaca P2 and P3.
  • Dampak: Sistem berjalan normal, namun beban CPU dan I/O jaringan pada setiap konsumen akan lebih tinggi karena mereka harus mengelola lebih dari satu partisi secara bergantian.

Skenario 2: Jumlah Konsumen Sama dengan Jumlah Partisi (Ideal/Optimized) #

Jika topik memiliki 4 partisi dan grup kita memiliki 4 konsumen (C1, C2, C3, C4).

  • Pembagian: Setiap konsumen akan mendapatkan tepat satu partisi (misalnya C1 membaca P0, C2 membaca P1, dst).
  • Dampak: Ini adalah skenario desain paling optimal di lingkungan produksi. Setiap konsumen memiliki fokus tunggal, memaksimalkan throughput pemrosesan paralel secara efisien.

Skenario 3: Jumlah Konsumen Lebih dari Jumlah Partisi (Over-provisioned / Standby) #

Jika topik memiliki 4 partisi dan grup kita memiliki 5 konsumen (C1, C2, C3, C4, C5).

  • Pembagian: C1 hingga C4 masing-masing membaca satu partisi dari P0 hingga P3. Konsumen kelima (C5) tidak akan mendapatkan alokasi partisi sama sekali.
  • Dampak: C5 akan berada dalam status siaga (idle/standby). Ia tidak akan menerima pesan apa pun dari Kafka broker. Meskipun terkesan membuang-buang sumber daya komputasi, skenario ini sering digunakan secara sengaja untuk memberikan toleransi kegagalan instan. Jika C1 mendadak mati, C5 dapat langsung mengambil alih partisi P0 tanpa perlu menunggu proses penyediaan kontainer aplikasi baru dari awal.
flowchart TD
    subgraph SkenarioA["Skenario A: Konsumen < Partisi"]
        direction LR
        AP0["P0"]
        AP1["P1"]
        AP2["P2"]
        AP3["P3"]
        AC1["C1"]
        AC2["C2"]
        AP0 --> AC1
        AP1 --> AC1
        AP2 --> AC2
        AP3 --> AC2
    end

    subgraph SkenarioB["Skenario B: Konsumen = Partisi (Ideal)"]
        direction LR
        BP0["P0"]
        BP1["P1"]
        BP2["P2"]
        BP3["P3"]
        BC1["C1"]
        BC2["C2"]
        BC3["C3"]
        BC4["C4"]
        BP0 --> BC1
        BP1 --> BC2
        BP2 --> BC3
        BP3 --> BC4
    end

    subgraph SkenarioC["Skenario C: Konsumen > Partisi"]
        direction LR
        CP0["P0"]
        CP1["P1"]
        CP2["P2"]
        CP3["P3"]
        CC1["C1"]
        CC2["C2"]
        CC3["C3"]
        CC4["C4"]
        CC5["C5 (Idle / Standby)"]
        CP0 --> CC1
        CP1 --> CC2
        CP2 --> CC3
        CP3 --> CC4
        style CC5 stroke-dasharray:5,5,stroke:#c62828,stroke-width:2px
    end

    style SkenarioA stroke:#558b2f,stroke-width:2px
    style SkenarioB stroke:#2e7d32,stroke-width:2px
    style SkenarioC stroke:#37474f,stroke-width:2px

Peran Broker Coordinator dan Kelompok Kepemimpinan #

Mengoordinasikan banyak konsumen yang berjalan secara terdistribusi di berbagai server agar selalu sepakat mengenai siapa membaca partisi apa bukanlah perkara mudah. Untuk menyelesaikan masalah koordinasi ini tanpa memerlukan sistem koordinasi eksternal tambahan (seperti ZooKeeper secara langsung dari sisi klien), Kafka menerapkan mekanisme Group Coordinator dan Consumer Group Leader.

1. Group Coordinator (Peran dari sisi Broker) #

Setiap Consumer Group di dalam kluster Kafka akan ditugaskan ke salah satu broker yang bertindak sebagai Group Coordinator. Coordinator ini dipilih secara otomatis oleh Kafka berdasarkan fungsi hash dari nama group.id yang dipetakan ke partisi dari topik internal __consumer_offsets. Tugas utama Group Coordinator meliputi:

  • Menerima permintaan bergabung dari instansi konsumen baru.
  • Memantau kesehatan masing-masing konsumen melalui pertukaran sinyal detak jantung (heartbeat).
  • Mendeteksi jika ada anggota kelompok yang mati atau tidak merespons.
  • Memicu proses pembagian ulang partisi (rebalance) ketika keanggotaan grup berubah.

2. Group Leader (Peran dari sisi Klien Konsumen) #

Ketika beberapa konsumen mengirimkan permintaan bergabung (JoinGroup request) ke Group Coordinator, broker coordinator akan menunjuk salah satu dari konsumen tersebut sebagai Group Leader (biasanya adalah konsumen pertama yang berhasil terhubung). Perbedaan peran ini sangat unik di Kafka: Group Coordinator (broker) hanya bertugas mengelola keanggotaan grup, sedangkan tugas menghitung algoritma pembagian partisi diserahkan sepenuhnya kepada Consumer Group Leader (klien).

  • Mengapa demikian? Keputusan desain ini diambil agar proses pembagian partisi fleksibel. Jika algoritma pembagian partisi dijalankan di sisi broker, kita harus melakukan upgrade seluruh broker Kafka setiap kali ingin menerapkan strategi pembagian partisi yang baru. Dengan menyerahkan kalkulasi ini ke sisi klien, pengembang dapat dengan mudah mengganti strategi pembagian partisi (seperti RangeAssignor, RoundRobinAssignor, atau StickyAssignor) cukup dengan mengubah konfigurasi pustaka di kode aplikasi kita.

Siklus Protokol Komunikasi Keanggotaan Grup #

Alur di bawah ini menggambarkan bagaimana sebuah grup diinisialisasi hingga partisi berhasil dibagikan kepada anggota:

sequenceDiagram
    participant C1 as Consumer 1 (Leader)
    participant C2 as Consumer 2
    participant GC as Group Coordinator (Broker)

    Note over C1,C2: Tahap 1: Mengirim JoinGroup Request
    C1->>GC: JoinGroup (Group ID: billing-service)
    C2->>GC: JoinGroup (Group ID: billing-service)
    
    Note over GC: Menunggu seluruh anggota terdaftar<br/>Menunjuk Consumer 1 sebagai Group Leader
    GC-->>C1: JoinGroup Response (Ditunjuk sebagai Leader + Daftar Anggota)
    GC-->>C2: JoinGroup Response (Ditunjuk sebagai Member)

    Note over C1: Menjalankan Algoritma Assignor<br/>(C1 ke P0, P1, C2 ke P2, P3)

    Note over C1,C2: Tahap 2: Sinkronisasi Pembagian (SyncGroup)
    C1->>GC: SyncGroup (Melampirkan Hasil Pembagian Partisi)
    C2->>GC: SyncGroup (Permintaan kosong / Menunggu instruksi)

    Note over GC: Menyimpan state pembagian ke __consumer_offsets
    GC-->>C1: SyncGroup Response (Menerima alokasi: P0, P1)
    GC-->>C2: SyncGroup Response (Menerima alokasi: P2, P3)

Konfigurasi Deteksi Kesehatan dan Batas Waktu (Timeout Configuration) #

Setelah kelompok konsumen terbentuk dan aktif memproses data, setiap konsumen harus secara berkala meyakinkan Group Coordinator bahwa mereka masih hidup dan bekerja dengan baik. Koordinasi ini diatur oleh tiga konfigurasi penting berikut:

  1. heartbeat.interval.ms
    • Deskripsi: Interval waktu seberapa sering konsumen mengirimkan sinyal detak jantung (heartbeat) ke Group Coordinator.
    • Nilai Default: 3.000 ms (3 detik). Sinyal ini dikirimkan secara otomatis di latar belakang oleh utas heartbeat internal klien.
  2. session.timeout.ms
    • Deskripsi: Batas waktu maksimal bagi Group Coordinator untuk menunggu datangnya sinyal heartbeat dari konsumen sebelum menganggap konsumen tersebut mati.
    • Nilai Default: 45.000 ms (45 detik) pada Kafka modern.
    • Aturan: Nilai ini harus lebih besar dari heartbeat.interval.ms (biasanya disetel dengan rasio 1:3). Jika Group Coordinator tidak menerima heartbeat dari konsumen selama durasi ini, broker akan mengeluarkan konsumen tersebut dari grup dan memicu rebalance.
  3. max.poll.interval.ms
    • Deskripsi: Batas waktu maksimal jeda antar pemanggilan fungsi .poll() di utas utama aplikasi kita.
    • Nilai Default: 300.000 ms (5 menit).
    • Penting: Ini adalah mekanisme deteksi kegagalan logika aplikasi (livelock). Jika thread utama aplikasi kita sibuk memproses data yang sangat berat atau mengalami kebuntuan (deadlock), ia tidak akan memanggil .poll() berikutnya tepat waktu meskipun utas heartbeat latar belakang masih aktif mengirimkan sinyal hidup ke broker. Jika batas 5 menit ini terlampaui, konsumen dianggap mandek, ia akan dikeluarkan dari grup secara paksa, dan partisi yang dipegangnya akan dialihkan ke konsumen lain.

Skenario Dinamis: Scale-Up, Scale-Down, dan Toleransi Kegagalan #

Mari kita bedah secara kronologis apa yang terjadi di balik layar kluster Kafka ketika terjadi perubahan dinamis pada keanggotaan Consumer Group kita.

Skenario 1: Penambahan Konsumen Baru (Scale-Up / Penskalaan Naik) #

Bayangkan kita memulai dengan satu konsumen C1 yang membaca dari topik dengan 3 partisi (P0, P1, P2).

  1. Keadaan Awal: C1 memegang seluruh partisi: P0, P1, dan P2.
  2. Konsumen Baru Bergabung: Kita menyalakan instansi aplikasi kedua, C2, dengan group.id yang sama.
  3. Pemberitahuan Rebalance: C2 mengirimkan request JoinGroup ke Group Coordinator. Coordinator menyadari ada anggota baru dan menandai grup dalam status rebalance. Pada panggilan .poll() berikutnya dari C1, broker mengembalikan kode instruksi khusus yang memberi tahu C1 untuk melepaskan partisi yang dipegangnya.
  4. Pelepasan Partisi (Revocation): C1 berhenti membaca data baru, mengomit offset terakhirnya ke broker, dan melepaskan kepemilikan atas partisi P0, P1, dan P2.
  5. Pembagian Ulang: Kedua konsumen mengirimkan request JoinGroup baru. Coordinator memilih C1 sebagai leader untuk membagikan partisi menggunakan algoritma terpilih. Misalnya, hasil pembagiannya adalah: C1 memegang P0 dan P1, sedangkan C2 memegang P2.
  6. Selesai: Setelah fase SyncGroup, masing-masing konsumen mulai membaca dari partisi baru mereka dari offset komit terakhir yang valid.

Skenario 2: Kegagalan Konsumen (Crash / Scale-Down) #

Bayangkan kita memiliki 3 konsumen (C1, C2, C3) yang masing-masing membaca satu partisi (P0, P1, P2).

  1. Kegagalan Terjadi: Server yang menjalankan konsumen C3 mendadak mati total karena kegagalan perangkat keras. Sinyal heartbeat dari C3 berhenti dikirimkan ke Group Coordinator.
  2. Timeout Terdeteksi: Group Coordinator menunggu hingga batas waktu session.timeout.ms (misalnya 45 detik) terlampaui. Selama 45 detik ini, data pada partisi P2 tidak ada yang memproses sama sekali (mengalami lag).
  3. Memicu Rebalance: Setelah 45 detik berlalu tanpa heartbeat, Coordinator secara resmi menyatakan C3 keluar dari grup. Coordinator memicu proses rebalance untuk mendistribusikan ulang partisi P2.
  4. Alokasi Ulang: Konsumen C1 dan C2 berkoordinasi ulang dengan Coordinator. Salah satu dari mereka (misalnya C1) ditugaskan untuk mengambil alih partisi P2 di samping partisi P0 yang sudah dimilikinya.
  5. Pemulihan: C1 membaca offset komit terakhir dari partisi P2 di topik __consumer_offsets dan melanjutkan pemrosesan data yang tertunda. Jaringan pipeline kembali berjalan normal dengan kapasitas pemrosesan yang berkurang menjadi 2 konsumen.

Kode Penerapan dan Deteksi Masalah Rebalance Liar #

Masalah paling umum yang dialami oleh para developer di lingkungan produksi adalah terjadinya Rebalance Liar / Tidak Terduga (Excessive / Unexpected Rebalances). Masalah ini biasanya dipicu oleh ketidakselarasan antara kecepatan pemrosesan data aplikasi dengan konfigurasi max.poll.interval.ms.

Java SDK Anti-Pattern: Mengunci Thread Utama #

Kode berikut menunjukkan kesalahan fatal di mana konsumen memproses data secara lambat pada thread utama poll loop, memicu pengeluaran paksa konsumen dari grup.

// ANTI-PATTERN: Menjalankan pemrosesan lambat langsung di thread poll loop utama
Properties props = new Properties();
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put(ConsumerConfig.GROUP_ID_CONFIG, "payment-processor");
props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "false");
props.put(ConsumerConfig.MAX_POLL_INTERVAL_MS_CONFIG, "300000"); // 5 Menit limit
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());

KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
consumer.subscribe(Collections.singletonList("payment-events"));

try {
    while (true) {
        ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
        for (ConsumerRecord<String, String> record : records) {
            // ✗ JANGAN: Melakukan panggilan API eksternal yang lambat di thread utama.
            // Jika satu record butuh waktu 10 detik dan poll() mengembalikan 50 records,
            // total waktu pemrosesan adalah 500 detik (8.3 menit).
            // Ini akan melampaui max.poll.interval.ms (5 menit), memicu CommitFailedException
            // dan menyebabkan konsumen dikeluarkan dari grup secara berulang (Rebalance Loop).
            processPaymentWithExternalGateway(record.value());
            consumer.commitSync();
        }
    }
} finally {
    consumer.close();
}

Java SDK Solusi: Pembatasan Batch Size & Optimasi Waktu Pemrosesan #

Untuk mengatasi masalah rebalance loop di atas, kita dapat menggunakan pendekatan pembatasan jumlah record yang ditarik dalam sekali poll melalui konfigurasi max.poll.records, atau mendelegasikan pemrosesan ke worker thread pool eksternal sambil berhati-hati dalam mengelola commit offset.

Berikut adalah contoh solusi yang aman dan direkomendasikan dengan membatasi ukuran batch agar pemrosesan terjamin selesai sebelum batas timeout:

// BENAR: Mengontrol volume data per poll dan menyelaraskan parameter batas timeout
Properties props = new Properties();
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put(ConsumerConfig.GROUP_ID_CONFIG, "payment-processor");
props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "false");

// ✓ Membatasi hanya menarik maksimal 10 records dalam sekali poll
props.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, "10");

// ✓ Memberikan waktu toleransi pemrosesan hingga 10 menit
props.put(ConsumerConfig.MAX_POLL_INTERVAL_MS_CONFIG, "600000"); 

// ✓ Mengatur deteksi hilangnya node aplikasi lebih cepat (15 detik)
props.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, "15000");
props.put(ConsumerConfig.HEARTBEAT_INTERVAL_MS_CONFIG, "5000");

props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());

KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
consumer.subscribe(Collections.singletonList("payment-events"));

try {
    while (true) {
        ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
        for (ConsumerRecord<String, String> record : records) {
            // ✓ Aman: Maksimal 10 record * 10 detik = 100 detik (1.6 menit).
            // Ini jauh di bawah ambang batas max.poll.interval.ms yang bernilai 10 menit (600.000 ms).
            processPaymentWithExternalGateway(record.value());
        }
        // ✓ Commit dilakukan per batch setelah seluruh records di poll tersebut sukses diproses
        consumer.commitSync();
    }
} catch (Exception e) {
    log.error("Terjadi kegagalan pemrosesan pesan", e);
} finally {
    // ✓ Selalu tutup konsumen secara bersih agar menginformasikan Group Coordinator
    // bahwa konsumen ini sengaja keluar, memangkas waktu tunggu session timeout.
    consumer.close();
}

Kapan Menghindari Penggunaan Consumer Group? #

Meskipun Consumer Group sangat bermanfaat untuk load balancing data, ada skenario tertentu di mana kita justru tidak boleh menggunakannya.

TETAP gunakan Consumer Group jika:
  ✓ Kita ingin mendistribusikan beban pemrosesan pesan ke banyak instansi aplikasi secara merata.
  ✓ Kita ingin sistem secara otomatis mengelola pemulihan partisi saat ada node aplikasi yang crash.
  ✓ Kita memerlukan jaminan bahwa setiap pesan hanya diproses oleh satu instansi di dalam grup.

JANGAN gunakan Consumer Group (Gunakan Direct Assignment / Simple Consumer) jika:
  ✗ Kita ingin setiap instansi aplikasi menerima seluruh pesan dari semua partisi (misalnya untuk memperbarui memori cache lokal di masing-masing server microservices secara sinkron).
  ✗ Kita ingin mengontrol secara manual penugasan partisi spesifik ke instansi tertentu secara statis tanpa ada proses rebalance otomatis.

Jika kita berada pada skenario kedua di atas, alih-alih memanggil consumer.subscribe(), kita harus menggunakan fungsi penugasan langsung:

// BENAR: Menggunakan direct assign untuk kontrol penuh tanpa proses rebalance otomatis
TopicPartition partition0 = new TopicPartition("payment-events", 0);
// ✓ Menugaskan konsumen ini secara spesifik hanya membaca partisi 0
consumer.assign(Collections.singletonList(partition0));

Ringkasan #

  • Skalabilitas Horisontal — Consumer Group memungkinkan beberapa instansi aplikasi dengan Group ID yang sama berkolaborasi membagi beban pemrosesan partisi suatu topik secara dinamis.
  • Jaminan Satu Partisi Satu Konsumen — Aturan dasar Kafka membatasi satu partisi hanya dikonsumsi oleh satu instansi dalam satu grup pada satu waktu untuk menjamin urutan pesan tetap terjaga kronologis.
  • Group Coordinator & Leader — Broker koordinator mengelola status keanggotaan grup, sedangkan konsumen pemimpin (Group Leader) bertugas menghitung dan mendistribusikan pembagian partisi.
  • Deteksi Kegagalan Aktif — Kombinasi parameter heartbeat.interval.ms dan session.timeout.ms digunakan coordinator untuk mendeteksi hilangnya respon instansi konsumen secara cepat.
  • Livelock & Deadlock Protection — Properti max.poll.interval.ms bertindak sebagai pelindung untuk mengeluarkan konsumen dari grup jika thread utama mandek saat memproses data bisnis yang lambat.
  • Rebalance Overhead — Setiap kali anggota grup bertambah atau berkurang, Kafka memicu proses rebalance yang menghentikan sementara proses pembacaan data (stop-the-world).
  • Penyelamatan Rebalance Loop — Masalah rebalance berulang diatasi dengan mengecilkan max.poll.records atau meningkatkan nilai parameter max.poll.interval.ms agar sesuai dengan durasi logika bisnis.

← Sebelumnya: Offset Management   Berikutnya: Partition Assignment Strategy →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact