Broker #
Di dalam ekosistem Apache Kafka, Broker adalah istilah untuk satu instance server fisik atau virtual yang bertugas menerima event dari produsen, menulisnya secara persisten ke penyimpanan disk lokal, dan melayani permintaan pembacaan data dari konsumen. Kluster Kafka terdiri dari beberapa broker yang saling berkoordinasi untuk mendistribusikan beban kerja secara seimbang dan toleran terhadap kegagalan. Memahami fungsi internal broker, mulai dari struktur penyimpanan fisik di tingkat sistem berkas (file system), koordinasi metadata, hingga cara mengalokasikan memori sistem secara optimal adalah kunci penting bagi kita untuk menjaga performa kluster tetap stabil di bawah beban kerja produksi yang sangat berat.
Peran Utama Broker Kafka #
Secara fungsional, broker Kafka dirancang sebagai server yang sangat efisien dan relatif sederhana (dumb broker, smart client). Berbeda dengan broker pesan lain yang harus melacak pesan mana yang sudah dibaca oleh masing-masing konsumen di memori server, broker Kafka tidak menyimpan informasi state pembacaan konsumen sama sekali.
Tugas utama broker Kafka berfokus pada tiga hal:
- Penerimaan Data: Menerima paket biner pesan dari produsen dan menulisnya secepat mungkin ke dalam segmen log partisi di disk lokal menggunakan operasi I/O sekuensial.
- Penyimpanan Data: Mengelola siklus hidup penyimpanan berkas data berdasarkan batas retensi (waktu dan ukuran) yang dikonfigurasi.
- Penyaluran Data: Melayani permintaan penarikan data dari konsumen dengan memanfaatkan memori OS Page Cache dan teknik Zero-Copy untuk mengirimkan byte data biner langsung ke kartu jaringan (Network Interface Card) tanpa melalui pemrosesan CPU di user space JVM.
Struktur Fisik Penyimpanan Data (Log Directory) #
Ketika kita menentukan direktori penyimpanan data Kafka melalui parameter log.dirs di file konfigurasi server.properties, Kafka akan membuat struktur direktori khusus untuk setiap partisi dari topik yang dikelolanya. Nama folder penyimpanan fisik diatur menggunakan format:
$$\text{nama-topik}-\text{indeks-partisi}$$
Sebagai contoh konkret, jika kita memiliki topik prod.finance.payment.fact.transaction-completed dengan 3 partisi, broker yang menyimpan partisi tersebut akan memiliki folder bernama prod.finance.payment.fact.transaction-completed-0, prod.finance.payment.fact.transaction-completed-1, dan seterusnya.
Di dalam setiap folder partisi tersebut, data disimpan dalam bentuk segmen-segmen berkas biner kecil yang terbagi menjadi tiga jenis file utama:
flowchart TD
subgraph FolderPartisi ["Folder Fisik Partisi (e.g. topik-transaksi-0)"]
direction TB
LogFile["File Segmen Log (.log) <br/> (Berisi payload biner event sebenarnya)"]
IndexFile["File Indeks Offset (.index) <br/> (Memetakan Offset ke posisi byte fisik di file .log)"]
TimeIndexFile["File Indeks Waktu (.timeindex) <br/> (Memetakan Timestamp ke Offset pesan)"]
end
1. File Segmen Log (.log)
#
File ini berisi kumpulan event biner sebenarnya yang ditulis secara berurutan (append-only). Secara bawaan, ketika ukuran file log mencapai 1 GB (diatur oleh log.segment.bytes), Kafka akan menutup file tersebut, menjadikannya berkas baca-saja (read-only), dan membuka berkas segmen aktif baru yang kosong untuk menerima penulisan data berikutnya.
2. File Indeks Offset (.index)
#
Membaca file log berukuran gigabyte dari awal untuk mencari satu offset tertentu adalah operasi yang sangat lambat. Untuk mempercepat pencarian, Kafka membuat file indeks khusus.
Namun, alih-alih mengindeks setiap pesan (yang akan menghabiskan ruang disk), Kafka menggunakan Sparse Index (indeks jarang). Kafka hanya mencatat indeks setiap kelipatan ukuran byte data tertentu (diatur oleh log.index.interval.bytes, default 4 KB). File indeks ini memetakan nomor offset secara langsung ke posisi byte fisik di dalam berkas .log. Konsumen dapat melompat ke posisi byte terdekat dari offset target secara instan ($O(1)$) menggunakan pencarian biner di memori.
3. File Indeks Waktu (.timeindex)
#
File ini digunakan untuk mencari data berdasarkan stempel waktu (timestamp). File .timeindex memetakan nilai stempel waktu ke nomor offset yang sesuai. Ini sangat berguna ketika aplikasi konsumen ingin memutar ulang (replay) data mulai dari waktu tertentu, misalnya “baca ulang seluruh transaksi dari hari kemarin pukul 08:00”.
Manajemen Replikasi Partisi (Leader vs Follower) #
Di dalam kluster terdistribusi, kita tidak boleh bergantung pada satu server tunggal karena server fisik rentan mengalami mati mendadak, kerusakan disk, atau gangguan daya. Kafka mengatasi ini dengan mereplikasi partisi topik ke beberapa broker yang berbeda.
Dalam mengelola replikasi partisi ini, broker Kafka membagi perannya menjadi dua:
flowchart LR
subgraph Client ["Klien Aplikasi"]
Producer["Producer"]
Consumer["Consumer"]
end
subgraph KafkaBrokers ["Kluster Broker Kafka"]
direction TB
subgraph Broker1 ["Broker 1 (Server A)"]
LeaderPart[("Partisi 0 (Leader)")]
end
subgraph Broker2 ["Broker 2 (Server B)"]
FollowerPart1[("Partisi 0 (Replica / Follower)")]
end
subgraph Broker3 ["Broker 3 (Server C)"]
FollowerPart2[("Partisi 0 (Replica / Follower)")]
end
end
Producer -->|Tulis Data ke Leader| LeaderPart
Consumer -->|Baca Data dari Leader| LeaderPart
FollowerPart1 -. "Tarik Data Replikasi (Pull)" .-> LeaderPart
FollowerPart2 -. "Tarik Data Replikasi (Pull)" .-> LeaderPart
1. Broker Leader #
Untuk setiap partisi, salah satu broker yang menyimpan replikanya akan ditunjuk sebagai Leader. Seluruh aktivitas penulisan data dari produsen dan pembacaan data dari konsumen secara bawaan wajib diarahkan langsung ke broker Leader ini. Broker Leader memegang kendali penuh atas kebenaran urutan data log partisi tersebut.
2. Broker Follower #
Broker replika lainnya bertindak sebagai Follower. Mereka bersikap pasif layaknya konsumen internal; tugas satu-satunya adalah mengirimkan permintaan penarikan data secara periodik ke broker Leader untuk menyalin segmen data terbaru ke disk lokal masing-masing.
In-Sync Replicas (ISR) #
Broker Leader terus memantau kemajuan replikasi dari para Follower. Jika sebuah Follower sukses menyalin data terbaru dalam batas waktu tertentu (diatur oleh replica.lag.time.max.ms, default 30 detik), Follower tersebut masuk ke dalam kelompok In-Sync Replicas (ISR). Jika ada Follower yang mengalami kemacetan jaringan atau disk yang lambat sehingga tertinggal lebih dari 30 detik, Leader akan mengeluarkannya dari kelompok ISR. Status keanggotaan ISR ini sangat penting karena hanya broker yang terdaftar di dalam ISR yang berhak dipilih menjadi Leader baru jika Leader saat ini mengalami crash.
Controller Broker: Otak Koordinasi Kluster #
Meskipun semua broker di dalam kluster Kafka dapat melayani klien, harus ada satu broker tunggal yang ditunjuk bertindak sebagai pemimpin koordinasi kluster. Broker ini disebut sebagai Controller.
Di dalam kluster berbasis KRaft (Kafka Raft Metadata Mode) modern, koordinasi ini dikelola secara elegan oleh sekelompok broker terpilih yang bertindak sebagai Controller Quorum.
Tugas utama Controller meliputi:
- Deteksi Kegagalan Broker: Memantau kesehatan seluruh broker di dalam kluster. Jika sebuah broker terdeteksi mati atau keluar dari kluster, Controller bertanggung jawab memberi tahu broker lain.
- Failover Pemimpin Partisi (Leader Election): Ketika broker yang memegang peran Leader untuk suatu partisi mati, Controller akan segera melihat daftar ISR dari partisi tersebut, memilih salah satu Follower yang sehat di dalam ISR untuk menjadi Leader baru, dan memublikasikan perubahan metadata kepemimpinan baru ini ke seluruh broker di kluster agar klien (produsen/konsumen) dapat memperbarui rute koneksi mereka.
- Pengelolaan Topik: Mengoordinasikan proses pembuatan topik baru, penghapusan topik, atau penambahan partisi baru di seluruh kluster.
Alokasi Memori Optimal: JVM Heap vs OS Page Cache #
Salah satu kesalahan paling fatal dan sering dilakukan oleh administrator sistem saat melakukan tuning server broker Kafka adalah mengalokasikan memori JVM Heap sebesar-besarnya (misalnya mengalokasikan 64 GB memori RAM server khusus untuk JVM Heap).
Meskipun Kafka ditulis menggunakan bahasa pemrograman Java, ia dirancang dengan filosofi arsitektur yang sangat merespek sistem operasi (OS-friendly architecture). Kafka sengaja didesain untuk menggunakan JVM Heap sekecil mungkin (rekomendasi ideal hanya 4 GB hingga 5 GB saja untuk proses broker umum) dan menyerahkan sisa kapasitas memori RAM fisik server yang melimpah untuk dikelola oleh OS Page Cache.
Mari kita pelajari mengapa alokasi memori ini sangat menentukan performa broker:
- Overhead Garbage Collection (GC): Jika kita menyetel JVM Heap terlalu besar (misal 32 GB atau lebih), ketika proses Garbage Collector JVM berjalan untuk membersihkan objek memori tidak terpakai, sistem akan mengalami jeda eksekusi (stop-the-world GC pause) yang sangat lama (bisa mencapai beberapa detik hingga menit). Selama jeda ini, broker akan berhenti merespon detak jantung dan koneksi klien, memicu rebalance liar dan kegagalan kluster. Dengan membatasi JVM heap di kisaran 5 GB, durasi jeda GC dapat ditekan di bawah beberapa milidetik saja.
- Pemanfaatan Page Cache untuk Zero-Copy: Data yang ditulis produsen ke disk sebenarnya pertama kali ditulis oleh OS ke dalam memori RAM yang bertindak sebagai Page Cache. Ketika konsumen meminta pembacaan data yang baru saja ditulis tersebut, Kafka tidak perlu membaca file fisik dari disk lambat. Kafka langsung membaca data dari Page Cache di RAM dan mengirimkannya langsung ke kartu jaringan menggunakan instruksi sistem Zero-Copy (
sendfilepada Linux). Ini menghasilkan kecepatan transfer data biner setara dengan performa memori RAM (RAM-speed transfer).
Rahasia Kecepatan Transfer Data: Teknologi Zero-Copy #
Untuk memahami mengapa teknik ini begitu revolusioner, mari kita bandingkan jalur transfer data biasa dengan Zero-Copy di bawah ini:
-
Jalur Membaca Data Konvensional (4 Kali Salin):
- OS membaca data dari Disk fisik ke Kernel Space Page Cache.
- Aplikasi (JVM) menyalin data tersebut dari Kernel Space ke User Space (JVM Heap) via syscall
read(). - Aplikasi menyalin kembali data dari JVM Heap ke Socket Buffer (Kernel Space) via syscall
write(). - OS menyalin data dari Socket Buffer ke NIC Buffer (Network Interface Card) sebelum dikirim ke kabel jaringan.
- Kerugian: Proses ini membutuhkan 4 kali penyalinan data di memori RAM dan memicu 4 kali pergantian konteks CPU (context switches) antara User Mode dan Kernel Mode. Ini memboroskan CPU cycles secara luar biasa.
-
Jalur Zero-Copy dengan
sendfile()(2 Kali Salin):- OS membaca data dari Disk ke Kernel Space Page Cache.
- Menggunakan instruksi
sendfile(), OS langsung menyalin deskriptor data dari Page Cache ke NIC Buffer secara langsung menggunakan perangkat keras DMA (Direct Memory Access).
- Keuntungan: Data sama sekali tidak pernah masuk ke memori User Space (JVM Heap). Tidak ada CPU cycles yang terbuang untuk menyalin byte data. Waktu pengerjaan terpangkas drastis dan throughput transfer jaringan meningkat secara spektakuler.
Siklus Hidup Shutdown Graceful (Controlled Shutdown) #
Sebagai administrator kluster, kita harus selalu mematikan broker secara bersih (graceful controlled shutdown) menggunakan sinyal SIGTERM atau perintah manajemen, bukan mematikan daya server secara paksa (SIGKILL).
Saat controlled shutdown berjalan:
- Broker akan menghentikan penerimaan koneksi klien baru.
- Broker akan melakukan migrasi kepemimpinan (leader migration) untuk seluruh partisi Leader yang dipegangnya ke broker Follower lain secara teratur.
- Seluruh sisa memori Page Cache yang belum tersimpan akan ditulis paksa (flushed) ke penyimpanan disk untuk mencegah korupsi data.
- Broker keluar dari keanggotaan kluster secara rapi.
- Manfaat: Meminimalkan waktu jeda pemulihan sistem, mencegah status data tidak konsisten, dan menghindari proses pemilihan leader darurat yang memicu rebalance tak terduga bagi klien.
Kesalahan Umum (Anti-pattern) dalam Pengelolaan Broker #
Berikut adalah kesalahan konfigurasi operasional broker Kafka yang wajib kita hindari:
1. Menjalankan Broker Menggunakan Shared Disk (NAS / SAN / NFS) #
Menyimpan direktori data log.dirs broker Kafka di dalam sistem penyimpanan jaringan bersama (Network Attached Storage) seperti NFS atau SAN dengan alasan kemudahan manajemen kapasitas.
Konsekuensi Kegagalan: Kafka dirancang dengan asumsi memiliki akses langsung ke disk lokal (direct attached storage) yang memiliki latensi I/O rendah dan konsisten. Menyimpan data log di NAS memicu perebutan bandwidth jaringan antara aktivitas replikasi internal Kafka dengan jalur I/O penyimpanan disk. Ini mengakibatkan latensi penulisan disk melonjak secara dramatis, memicu kegagalan sinkronisasi replikasi, mengeluarkan broker dari ISR, dan akhirnya membuat performa kluster menurun drastis atau mati total. Selalu gunakan piringan disk SSD/NVMe lokal yang terpasang langsung di server fisik broker.
// ANTI-PATTERN di file server.properties:
log.dirs=/mnt/shared-nfs/kafka-data // Menggunakan penyimpanan jaringan bersama (Sangat Berbahaya!)
// Solusi yang BENAR:
log.dirs=/var/lib/kafka/data // Selalu arahkan ke disk SSD/NVMe lokal server
2. Mengabaikan Batasan Limit File Descriptor di Linux (Open Files Limit) #
Menjalankan proses broker Kafka pada sistem operasi Linux dengan konfigurasi batas maksimum berkas terbuka (open files limits) default yang sangat rendah (biasanya default hanya 1024 berkas).
Konsekuensi Kegagalan: Seperti yang telah dibahas, setiap partisi topik membutuhkan minimal 3 berkas terbuka (.log, .index, .timeindex) secara terus-menerus. Jika kita memiliki ratusan partisi topik dan beberapa koneksi soket TCP dari klien aktif, broker akan segera menyentuh batas limit sistem operasi tersebut dan melemparkan error fatal java.io.IOException: Too many open files. Proses broker akan langsung mogok seketika. Pastikan batas berkas terbuka Linux dinaikkan minimal ke angka 65536 atau 100000 sebelum menjalankan Kafka.
Ringkasan #
- Definisi Broker — Broker adalah satu instance server fisik atau virtual di dalam kluster Kafka yang bertugas menerima, menyimpan, mereplikasi, dan menyalurkan aliran data event biner secara sekuensial dan efisien.
- Struktur Fisik — Data disimpan dalam folder partisi khusus tingkat sistem berkas yang terbagi menjadi segmen file
.log(payload biner), file.index(sparse index offset untuk pencarian cepat), dan file.timeindex(indeks stempel waktu).- Peran Replikasi — Replikasi partisi dikelola menggunakan skema Leader (melayani pembacaan/penulisan klien) dan Follower (menyalin data secara asinkron dari Leader). Broker replika yang sehat terdaftar di dalam kelompok In-Sync Replicas (ISR).
- Peran Controller — Controller adalah otak koordinasi kluster yang bertanggung jawab mendeteksi kegagalan broker, mengelola transisi kepemimpinan partisi, dan mengoordinasikan metadata kluster.
- Tuning Memori — Hindari alokasi JVM Heap yang terlalu besar demi mencegah jeda panjang Garbage Collection. Alokasikan JVM Heap secukupnya (4-5 GB) dan sisakan memori RAM server yang melimpah untuk OS Page Cache guna menunjang fitur transfer Zero-Copy.
- Gunakan Local Storage — Selalu gunakan penyimpanan SSD/NVMe lokal yang terpasang langsung pada server broker; jangan pernah menggunakan media penyimpanan jaringan bersama (NAS/SAN) karena dapat merusak performa I/O disk.