Broker Log: Mengonfigurasi dan Menganalisis Log Server Apache Kafka #
Dalam mengoperasikan Apache Kafka di skala produksi, kita sering kali dihadapkan pada situasi misterius di mana kinerja kluster tiba-tiba menurun atau salah satu broker terputus dari koordinasi kluster. Untuk melakukan diagnosis masalah (troubleshooting), instrumen pertama yang harus kita periksa adalah log operasional server broker (Broker Log). Berbeda dengan log data (log segments) yang menampung payload pesan asli dari produser, log server berisi pesan diagnostik dari mesin internal Kafka (seperti status replikasi, siklus hidup konsumen, otorisasi ACL, dan metadata pengawas).
Banyak tim DevOps pemula yang mencampuradukkan kedua istilah log ini atau membiarkan konfigurasi log server default berjalan di produksi. Akibatnya, disk server mereka cepat penuh oleh file log server raksasa yang tidak berotasi, atau sebaliknya, mereka kehilangan informasi berharga karena level logging disetel terlalu tinggi (WARN atau ERROR saja).
Dalam panduan ini, kita akan membedah perbedaan log data vs log server, menyusun konfigurasi log4j.properties yang optimal untuk produksi, mempelajari teknik mengubah level logging secara dinamis tanpa restart broker (Dynamic Log Level Tuning), serta mendekode pesan log server untuk memecahkan masalah produksi yang umum terjadi.
Membedakan Log Data vs Log Server #
Sebelum melangkah lebih jauh, sangat penting bagi kita untuk memisahkan kedua konsep log berikut karena kegagalan memahami perbedaan ini sering kali berujung pada kesalahan konfigurasi disk:
+---------------------------------------------------------------------------------+
| PERBEAAN UTAMA DUA JENIS LOG |
| |
| 1. LOG DATA (Data Log Segments) |
| * Jalur Properti: log.dirs=/var/lib/kafka/data |
| * Isi: Payload biner pesan asli dari produser (.log, .index, .timeindex) |
| * Pengaturan: log.retention.hours, log.retention.bytes |
| |
| 2. LOG SERVER (Server Operation Log) |
| * Konfigurasi: /etc/kafka/log4j.properties |
| * Isi: Teks logs diagnostik JVM Java/Scala (ReplicaManager, Controller, ZK) |
| * Pengaturan: FileSize, MaxBackupIndex, DailyRollingFileAppender |
+---------------------------------------------------------------------------------+
Log server ditulis oleh framework Log4j yang dibungkus oleh Java Virtual Machine (JVM). Log inilah yang akan menjadi fokus pembahasan kita untuk memantau kesehatan operasional broker.
Arsitektur Alur Logger Internal Kafka Broker #
Kafka membagi aktivitas pencatatannya ke dalam beberapa kategori logger khusus agar kita dapat memisahkan file output berdasarkan fungsinya.
Berikut adalah diagram alur logger internal Kafka menuju berkas log fisiknya:
flowchart TD
subgraph Subsystems ["Subsistem Broker Kafka"]
ReplicaMgr["Replica Manager (ISR)"]
Controller["Controller Manager (KRaft/ZK)"]
GroupCoord["Group Coordinator (Rebalance)"]
RequestLog["Network Request Processor"]
end
subgraph Log4jLoggers ["Log4j Logger Categories"]
StateLogger["state.change.logger"]
ContrLogger["kafka.controller"]
CoordLogger["kafka.coordinator"]
ReqLogger["kafka.request.logger"]
end
subgraph PhysicalFiles ["Berkas Log Fisik (Disk)"]
StateFile["/var/log/kafka/state-change.log"]
ServerFile["/var/log/kafka/server.log"]
RequestFile["/var/log/kafka/kafka-request.log"]
end
ReplicaMgr --> StateLogger
Controller --> ContrLogger
GroupCoord --> CoordLogger
RequestLog --> ReqLogger
StateLogger --> StateFile
ContrLogger --> ServerFile
CoordLogger --> ServerFile
ReqLogger --> RequestFile
Pemecahan kategori ini sangat membantu kita ketika ingin menaikkan tingkat kedetailan log untuk satu modul tertentu tanpa membanjiri modul lainnya dengan pesan yang tidak perlu.
Konfigurasi Produksi: log4j.properties yang Aman
#
Secara default, Kafka menulis seluruh log ke dalam satu file tunggal yang berputar setiap hari tanpa batas kapasitas. Di produksi, kita harus membatasi ukuran file maksimal menggunakan RollingFileAppender dengan setelan MaxFileSize dan MaxBackupIndex untuk mencegah disk penuh akibat kebocoran log.
Berikut adalah konfigurasi /etc/kafka/log4j.properties produksi yang telah dioptimalkan:
# ==============================================================================
# log4j.properties - KONFIGURASI PRODUKSI LOG SERVER KAFKA
# ==============================================================================
# 1. Definisikan Level Root Logger dan Appender Utama
log4j.rootLogger=INFO, kafkaAppender
# 2. Konfigurasi Appender Utama (server.log)
log4j.appender.kafkaAppender=org.apache.log4j.RollingFileAppender
log4j.appender.kafkaAppender.File=/var/log/kafka/server.log
# Batasi ukuran per file maksimal 100 MB
log4j.appender.kafkaAppender.MaxFileSize=100MB
# Simpan maksimal 10 file backup (total kapasitas maks 1 GB)
log4j.appender.kafkaAppender.MaxBackupIndex=10
log4j.appender.kafkaAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.kafkaAppender.layout.ConversionPattern=[%d] %p %m (%c)%n
# 3. Konfigurasi Appender Khusus Transisi Status (state-change.log)
log4j.logger.state.change.logger=INFO, stateChangeAppender
log4j.additivity.state.change.logger=false
log4j.appender.stateChangeAppender=org.apache.log4j.RollingFileAppender
log4j.appender.stateChangeAppender.File=/var/log/kafka/state-change.log
log4j.appender.stateChangeAppender.MaxFileSize=100MB
log4j.appender.stateChangeAppender.MaxBackupIndex=5
log4j.appender.stateChangeAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.stateChangeAppender.layout.ConversionPattern=[%d] %p %m (%c)%n
# 4. Konfigurasi Appender Khusus Controller (controller.log)
log4j.logger.kafka.controller=INFO, controllerAppender
log4j.additivity.kafka.controller=false
log4j.appender.controllerAppender=org.apache.log4j.RollingFileAppender
log4j.appender.controllerAppender.File=/var/log/kafka/controller.log
log4j.appender.controllerAppender.MaxFileSize=50MB
log4j.appender.controllerAppender.MaxBackupIndex=5
log4j.appender.controllerAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.controllerAppender.layout.ConversionPattern=[%d] %p %m (%c)%n
# 5. Batasi Verbosity Pustaka Pihak Ketiga (Zookeeper / Netty / Reflections)
log4j.logger.org.apache.zookeeper=WARN
log4j.logger.org.I0Itec.zkclient=WARN
log4j.logger.org.reflections=WARN
# 6. Logger Khusus untuk Keamanan (ACL & Otorisasi)
log4j.logger.kafka.authorizer.logger=INFO, authorizerAppender
log4j.additivity.kafka.authorizer.logger=false
log4j.appender.authorizerAppender=org.apache.log4j.RollingFileAppender
log4j.appender.authorizerAppender.File=/var/log/kafka/kafka-authorizer.log
log4j.appender.authorizerAppender.MaxFileSize=50MB
log4j.appender.authorizerAppender.MaxBackupIndex=5
log4j.appender.authorizerAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.authorizerAppender.layout.ConversionPattern=[%d] %p %m (%c)%n
Integrasi dengan Logrotate Sistem #
Untuk memastikan file log yang telah dirotasi dikompresi dengan aman untuk menghemat ruang disk, kita dapat membuat konfigurasi /etc/logrotate.d/kafka seperti berikut:
/var/log/kafka/*.log {
daily
rotate 7
copytruncate
compress
delaycompress
missingok
notifempty
}
Metode copytruncate sangat penting karena Kafka memegang deskriptor file log secara terus-menerus. Dengan menggunakan copytruncate, sistem operasi menyalin konten log aktif ke file baru dan mengosongkan file aktif saat ini tanpa memutuskan tautan proses JVM yang sedang menulis log.
Dynamic Log Level Tuning via CLI dan Code #
Ketika kluster mengalami kegagalan otorisasi atau masalah replikasi yang sangat kompleks, level logging INFO sering kali kurang memberikan detail error. Namun, kita tidak boleh merestart broker hanya untuk mengubah level log menjadi DEBUG karena restart akan memicu failover partisi, migrasi kepemimpinan, dan memperparah degradasi performa kluster secara keseluruhan.
Apache Kafka menyediakan API dinamis untuk merubah level logging logger tertentu secara langsung (on-the-fly).
Metode 1: Menggunakan CLI kafka-configs.sh
#
Kita dapat memodifikasi level logging secara dinamis menggunakan CLI bawaan Kafka. Perubahan ini dikomunikasikan melalui protokol Kafka AdminClient langsung ke broker tujuan dan diterapkan secara instan tanpa restart JVM.
-
Memeriksa Level Logger Saat Ini: Untuk melihat daftar logger aktif beserta levelnya pada broker dengan ID 1:
kafka-configs.sh --bootstrap-server localhost:9093 \ --command-config /etc/kafka/client.properties \ --describe \ --entity-type broker-loggers \ --entity-name 1 -
Mengubah Level Logger secara Dinamis: Jika kita ingin memantau detail request otorisasi ACL untuk melacak kegagalan otentikasi klien, ubah level
kafka.authorizer.loggermenjadiDEBUG:kafka-configs.sh --bootstrap-server localhost:9093 \ --command-config /etc/kafka/client.properties \ --alter \ --entity-type broker-loggers \ --entity-name 1 \ --add-config kafka.authorizer.logger=DEBUG -
Mengembalikan ke Level Semula: Setelah proses troubleshooting selesai, kita harus segera mengembalikannya ke level
INFOagar tidak membebani performa I/O disk broker:kafka-configs.sh --bootstrap-server localhost:9093 \ --command-config /etc/kafka/client.properties \ --alter \ --entity-type broker-loggers \ --entity-name 1 \ --add-config kafka.authorizer.logger=INFO
Metode 2: Mengubah Level Logger Secara Programmatic (Java AdminClient) #
Bagi kita yang bertindak sebagai tim SRE (Site Reliability Engineering) yang ingin membangun alat otomasi penalaan log (automatic log tuning tool), kita dapat memicu pengubahan logger level menggunakan Java AdminClient API secara terprogram:
package com.mycompany.kafka.admin;
import org.apache.kafka.clients.admin.AdminClient;
import org.apache.kafka.clients.admin.AlterConfigsResult;
import org.apache.kafka.common.config.ConfigResource;
import org.apache.kafka.clients.admin.ConfigEntry;
import org.apache.kafka.clients.admin.AlterConfigOp;
import java.util.*;
public class DynamicLoggerTuner {
private final AdminClient adminClient;
public DynamicLoggerTuner(Properties properties) {
this.adminClient = AdminClient.create(properties);
}
/**
* Mengubah level logger broker secara dinamis tanpa restart.
*
* @param brokerId ID dari broker Kafka yang ditargetkan
* @param loggerName Nama logger (misalnya "kafka.authorizer.logger")
* @param level Tingkat log baru (misalnya "DEBUG", "INFO", "WARN")
*/
public void setBrokerLoggerLevel(int brokerId, String loggerName, String level) throws Exception {
// 1. Definisikan tipe sumber daya sebagai BROKER_LOGGER
ConfigResource resource = new ConfigResource(
ConfigResource.Type.BROKER_LOGGER,
String.valueOf(brokerId)
);
// 2. Buat entri konfigurasi level logger baru
ConfigEntry loggerConfig = new ConfigEntry(loggerName, level);
// 3. Setel operasi pengubahan (SET)
AlterConfigOp op = new AlterConfigOp(loggerConfig, AlterConfigOp.OpType.SET);
Map<ConfigResource, Collection<AlterConfigOp>> configs = new HashMap<>();
configs.put(resource, Collections.singletonList(op));
// 4. Kirim request perubahan ke Broker secara asinkron
AlterConfigsResult result = adminClient.incrementalAlterConfigs(configs);
// Tunggu hingga konfirmasi jabat tangan sukses ke broker
result.all().get();
System.out.println("Berhasil merubah logger [" + loggerName + "] pada broker [" + brokerId + "] menjadi " + level);
}
public void close() {
if (adminClient != null) {
adminClient.close();
}
}
}
Pendekatan programmatic ini sangat aman jika kita pasangkan dengan sistem alert otomatis. Sebagai contoh, ketika tingkat kegagalan otorisasi melampaui batas tertentu, sistem dapat otomatis menaikkan level log authorizer ke DEBUG selama 15 menit, lalu menurunkannya kembali setelah mengumpulkan sampel log yang cukup.
Menganalisis Log Server untuk Troubleshooting Masalah Produksi #
Ketika kluster mengalami kegagalan operasional, kita harus mampu mengidentifikasi akar masalah secara cepat dengan mencocokkan pola pesan kesalahan yang muncul di file log. Berikut adalah pembahasan mendalam mengenai lima skenario kegagalan produksi yang paling sering terjadi, lengkap dengan analisis struktur log aslinya.
1. Masalah Replikasi: Shrinking ISR #
Skenario ini terjadi saat replikasi antar broker mengalami hambatan fisik, memaksa leader partisi mengeluarkan replika lambat dari kelompok ISR.
Contoh Pesan Log:
[2026-06-08 14:22:15,102] INFO [ReplicaManager broker=1] Shrinking ISR for partition payment.orders-0 to 1,2 (kafka.server.ReplicaManager)
Analisis Masalah:
- Identifikasi Awal: Partisi
payment.orders-0kehilangan salah satu replika aktifnya. Daftar ISR sebelumnya (misalnya berisi broker 1, 2, dan 3) menyusut menjadi hanya dihuni oleh broker 1 dan 2. Broker dengan ID 3 telah dinyatakan keluar dari ISR. - Akar Penyebab: Broker 3 kemungkinan mengalami salah satu dari masalah berikut:
- Jeda Garbage Collection yang sangat lama (stop-the-world pause) sehingga broker 3 gagal mengirimkan sinyal detak jantung (heartbeat) ke controller dalam kurun waktu
replica.lag.time.max.ms. - Kemacetan I/O disk pada partisi log data broker 3, menyebabkan thread replikasi (ReplicaFetcherThread) tertinggal jauh di belakang Log End Offset (LEO) milik leader.
- Masalah jaringan lokal (network packet loss) antara broker 1 dan broker 3.
- Jeda Garbage Collection yang sangat lama (stop-the-world pause) sehingga broker 3 gagal mengirimkan sinyal detak jantung (heartbeat) ke controller dalam kurun waktu
- Langkah Mitigasi:
- Periksa log garbage collection di broker 3. Jika durasi pause GC melebihi 5-10 detik, lakukan optimasi G1GC.
- Periksa latensi I/O disk dengan utilitas
iostatuntuk memantau apakah ada antrean tulis disk yang tinggi.
2. Masalah Konsumen: Rebalance Loop dan Session Timeouts #
Skenario ini sering dikeluhkan oleh pengembang ketika aplikasi konsumen mereka tampak berhenti memproses data dan terus-menerus melakukan proses penyeimbangan ulang (rebalance).
Contoh Pesan Log:
[2026-06-08 14:25:30,415] INFO [GroupCoordinator 1]: Preparing rebalance for group payment-processor in state PreparingRebalance with member client-1-8c4d21e8 (reason: Peer re-joined group) (kafka.coordinator.group.GroupCoordinator)
[2026-06-08 14:25:45,910] INFO [GroupCoordinator 1]: Member client-1-8c4d21e8 in group payment-processor has failed, removing from group (reason: join-group timeout) (kafka.coordinator.group.GroupCoordinator)
Analisis Masalah:
- Pemicu Awal: Group Coordinator pada Broker 1 mendeteksi bahwa salah satu anggota grup konsumen (
client-1-8c4d21e8) keluar atau terlambat merespons, memicu transisi ke fasePreparingRebalance. - Akar Penyebab:
- Properti
max.poll.interval.mspada sisi klien disetel terlalu rendah dibandingkan dengan waktu pemrosesan satu batch data. Jika konsumen memerlukan waktu 60 detik untuk memproses data dari satu panggilanpoll(), tetapimax.poll.interval.msdisetel hanya 30 detik, konsumen akan dianggap mati oleh coordinator. - Konsumen mengalami error di luar dugaan (out of memory) atau terhenti karena jeda GC lokal yang lama.
- Properti
- Langkah Mitigasi:
- Tingkatkan nilai
max.poll.interval.mspada konfigurasi klien agar memberikan toleransi waktu pemrosesan yang lebih panjang. - Alternatifnya, turunkan nilai
max.poll.recordsuntuk membatasi jumlah data yang ditarik dalam sekali poll sehingga pemrosesan selesai lebih cepat. - Pindahkan logika pemrosesan yang berat ke dalam thread pool terpisah (worker threads) dan gunakan thread utama konsumen hanya untuk melakukan poll dan commit offset.
- Tingkatkan nilai
3. Masalah Log Compaction: Cleaner Starved atau Thread Crash #
Skenario ini terjadi ketika proses pembersihan log kotor (log compaction) pada topik dengan kebijakan retensi compact mengalami kegagalan.
Contoh Pesan Log:
[2026-06-08 14:28:10,005] WARN [LogCleaner 1]: Cleaner 1 is starved on log directory /var/lib/kafka/data/tenant-a.logs-0 (kafka.log.LogCleaner)
[2026-06-08 14:28:15,310] ERROR [LogCleaner 1]: Error due to local offset map overflow (kafka.log.LogCleaner)
Analisis Masalah:
- Pemicu Awal: Thread
LogCleanermemperingatkan bahwa pembersihan log pada direktoritenant-a.logs-0tertahan (starved) dan tidak dapat memproses pemadatan data. - Akar Penyebab:
- Jumlah kunci unik (unique keys) pada partisi tersebut melebihi kapasitas memori dari peta offset pencatat (
SkimpyOffsetMap). Alokasi memori deduplikasi default (log.cleaner.dedupe.buffer.sizeyang bernilai 128 MB) tidak cukup untuk menampung seluruh representasi hash kunci pesan. - Ketika buffer penuh sebelum seluruh segmen log terpetakan, proses pembersihan akan macet atau thread LogCleaner akan mengalami crash dengan pesan
ERROR.
- Jumlah kunci unik (unique keys) pada partisi tersebut melebihi kapasitas memori dari peta offset pencatat (
- Langkah Mitigasi:
- Tingkatkan kapasitas memori deduplikasi cleaner di berkas
server.properties:log.cleaner.dedupe.buffer.size=536870912 # Naikkan menjadi 512 MB - Tambahkan jumlah thread pembersih log dengan menyetel
log.cleaner.threads=2atau lebih untuk mempercepat proses pemadatan paralel.
- Tingkatkan kapasitas memori deduplikasi cleaner di berkas
4. Masalah KRaft Metadata: Recovery Latency dan Socket Depletion #
Untuk kluster modern yang menggunakan mode KRaft (tanpa ZooKeeper), melacak koordinasi metadata sangat bergantung pada log controller KRaft.
Contoh Pesan Log:
[2026-06-08 14:31:02,110] INFO [MetadataLoader] Metadata loader has processed up to offset 1045230 in 150 ms (org.apache.kafka.image.loader.MetadataLoader)
[2026-06-08 14:31:05,420] WARN [RaftManager] Raft leader 1 failed to heartbeat to voter 2 within the timeout of 3000 ms (org.apache.kafka.raft.KafkaRaftClient)
Analisis Masalah:
- Pemicu Awal: Controller KRaft mendeteksi keterlambatan pemrosesan metadata atau kegagalan detak jantung antara voter quorum KRaft.
- Akar Penyebab:
- Aliran perubahan metadata terlalu masif (misalnya akibat pembuatan ribuan partisi topik secara dinamis dalam waktu singkat), sehingga loader metadata mengalami antrean pemrosesan (recovery latency).
- Node controller kekurangan alokasi thread atau mengalami kehabisan socket koneksi (file descriptor depletion) akibat membludaknya jumlah koneksi dari klien eksternal.
- Langkah Mitigasi:
- Pisahkan node KRaft controller secara fisik dari node data broker. Jangan gabungkan peran broker dan controller di server yang sama untuk kluster skala besar.
- Pastikan parameter OS
ulimit -ndisetel minimal 100.000 untuk mencegah errorToo many open filespada socket internal quorum KRaft.
5. Masalah Keamanan: ACL Authorization Failures #
Kita harus memantau log keamanan secara ketat untuk mendeteksi upaya akses tidak sah oleh klien ilegal atau kesalahan konfigurasi kredensial aplikasi.
Contoh Pesan Log:
[2026-06-08 14:35:10,218] INFO Principal = User:CN=payment-app,O=MyCorp is Denied Operation = Write for Resource = Topic:payment.orders (kafka.authorizer.logger)
Analisis Masalah:
- Pemicu Awal: Pengguna dengan sertifikat SSL
User:CN=payment-app,O=MyCorpditolak (Denied) saat mencoba melakukan operasiWriteke topikpayment.orders. - Akar Penyebab:
- Klien menggunakan nama pengguna yang benar, tetapi kebijakan ACL (Access Control List) di Kafka belum diperbarui untuk mengizinkan operasi penulisan pada topik tersebut.
- Terjadi kesalahan penulisan nama topik di sisi kode aplikasi klien (misalnya salah menulis nama topik menjadi
payment.orderspadahal seharusnyapayment-orders-v2).
- Langkah Mitigasi:
- Jalankan perintah CLI berikut untuk memverifikasi daftar ACL topik target:
kafka-acls.sh --bootstrap-server localhost:9093 \ --command-config /etc/kafka/client.properties \ --list \ --topic payment.orders - Berikan izin akses tulis yang sah jika identitas klien terbukti valid:
kafka-acls.sh --bootstrap-server localhost:9093 \ --command-config /etc/kafka/client.properties \ --add \ --allow-principal User:CN=payment-app,O=MyCorp \ --operation Write \ --topic payment.orders
- Jalankan perintah CLI berikut untuk memverifikasi daftar ACL topik target:
Kepatuhan Operasional dan Checklist Audit Log Server #
Untuk menjamin keandalan sistem pemantauan kita, lakukan audit rutin terhadap log server Kafka menggunakan checklist kepatuhan produksi berikut:
| No | Item Kepatuhan Audit Log Server | Metode Verifikasi | Status |
|---|---|---|---|
| 1 | Rotasi Log Aktif | Verifikasi bahwa seluruh appender di log4j.properties bertipe RollingFileAppender dan membatasi ukuran maksimal file. |
[ ] |
| 2 | Batas Ukuran Log Terpenuhi | Pastikan parameter MaxFileSize disetel maksimal 100MB dan MaxBackupIndex disetel maksimal 10 untuk mengontrol konsumsi ruang disk. |
[ ] |
| 3 | Pemisahan File Log Khusus | Pastikan log controller, log state-changes, dan log otorisasi diarahkan ke file log fisiknya masing-masing agar tidak mengotori server.log. |
[ ] |
| 4 | Pembersihan Log via Cron | Konfigurasikan daemon logrotate sistem untuk mengompresi file log backup yang sudah tua dan menghapusnya setelah batas waktu retensi. |
[ ] |
| 5 | Keamanan Akses File Log | Hak akses file log server di /var/log/kafka/ hanya boleh dibuka untuk user sistem kafka (chmod 640). |
[ ] |
| 6 | Level Log Default Aman | Pastikan default root logger disetel pada level INFO untuk mencegah penurunan performa akibat penulisan log berlebih di level DEBUG/TRACE. |
[ ] |
Ringkasan #
- Pisahkan Konsep Log — Selalu pisahkan pemahaman antara log data segment (yang menampung payload pesan terkompresi dari klien) dengan log server Log4j (yang menampung pesan diagnostik JVM).
- Batasi Ukuran File — Jangan biarkan log server tumbuh tanpa batas di disk broker. Gunakan
RollingFileAppenderdengan batas kapasitas maksimal untuk mengamankan sisa ruang disk broker.- Tuning Log Dinamis — Manfaatkan perintah
kafka-configs.shatau JavaAdminClientuntuk menaikkan level log keDEBUGsaat melakukan troubleshooting tanpa perlu merestart JVM broker.- Dekode Secara Akurat — Pelajari pesan log kunci seperti
Shrinking ISR,Preparing rebalance, danCleaner starveduntuk mempercepat deteksi akar masalah saat terjadi insiden di produksi.