Size-Based Retention #
Mengelola ketersediaan ruang penyimpanan fisik pada kluster broker adalah salah satu tanggung jawab paling kritis bagi administrator sistem Apache Kafka. Mengandalkan kebijakan retensi berbasis waktu saja (Time-Based Retention) sangatlah berisiko di lingkungan produksi. Bayangkan jika sistem kita tiba-kira mengalami lonjakan lalu lintas data (traffic spike) hingga 10 kali lipat akibat promosi penjualan atau serangan DDoS. Dalam hitungan jam, volume data yang sangat besar akan memenuhi kapasitas hard disk broker sebelum batas waktu retensi (misalnya 7 hari) tercapai. Jika kapasitas disk terisi 100%, broker Kafka akan mengalami kegagalan fatal (crash) dan merusak seluruh operasi kluster. Untuk mengantisipasi bencana ini, Kafka menyediakan kebijakan penyelamat kedua: Size-Based Retention (Retensi Berbasis Ukuran).
Membedah Parameter Retensi Ukuran: Batasan Per Partisi #
Ada dua parameter utama yang mengontrol retensi berbasis ukuran, baik di tingkat konfigurasi global kluster maupun di tingkat konfigurasi kustom topik.
1. log.retention.bytes (Batas Ukuran Partisi)
#
Parameter ini menetapkan kapasitas ruang disk maksimum yang diizinkan untuk satu partisi tunggal, bukan untuk total keseluruhan topik! Ini adalah jebakan klasik yang sering mengecoh para engineer sistem.
Rumus Perhitungan Total Penggunaan Disk Topik #
Jika kita memiliki topik dengan nama user-clicks yang dikonfigurasi dengan:
partitions=12replication.factor=3log.retention.bytes=10.737.418.240(10 GB)
Maka, batas maksimum kapasitas disk total yang dapat dikonsumsi oleh topik tersebut di seluruh kluster adalah:
$$\text{Disk Total} = \text{log.retention.bytes} \times \text{Partitions} \times \text{Replication Factor}$$
$$\text{Disk Total} = 10 \text{ GB} \times 12 \times 3 = 360 \text{ GB}$$
Jadi, meskipun kita menetapkan angka 10 GB pada parameter, kita harus memastikan infrastruktur kluster kita memiliki ruang kosong minimal 360 GB khusus untuk topik tersebut.
2. log.segment.bytes (Batas Ukuran Segmen)
#
Parameter ini menentukan ukuran maksimum dari satu berkas segmen log fisik sebelum ditutup (rolled). Secara bawaan, Kafka menetapkan:
$$\text{log.segment.bytes} = 1.073.741.824 \text{ bytes (1 GB)}$$
Artinya, setiap kali berkas log aktif mencapai ukuran 1 GB, berkas tersebut akan ditutup menjadi berkas read-only, dan Kafka akan membuka segmen baru untuk melanjutkan penulisan.
Interaksi Logis: “Whichever Comes First” (Siapa Cepat Dia Dapat) #
Di lingkungan produksi yang ideal, kita sangat direkomendasikan untuk mengaktifkan kebijakan retensi waktu (log.retention.ms) dan retensi ukuran (log.retention.bytes) secara bersamaan pada topik sensitif.
Kafka mengevaluasi kedua kebijakan ini dengan prinsip “Whichever Comes First” (Mana yang Tercapai Lebih Dahulu).
Contoh Skenario Simulasi #
Kita memiliki topik dengan konfigurasi:
log.retention.ms=604800000(7 Hari)log.retention.bytes=5368709120(5 GB per partisi)
Mari kita tinjau dua kondisi aliran data yang berbeda:
- Kasus A: Throughput Tinggi (Traffic Spike) Laju data masuk sangat deras sebesar 3 GB per hari. Pada hari kedua, total data di partisi mencapai 6 GB. Karena batas ukuran 5 GB terlewati sebelum batas 7 hari tercapai, Kafka akan langsung memicu penghapusan segmen tidak aktif tertua untuk mengembalikan total ukuran partisi di bawah 5 GB. Data tertua di sini hanya sempat bertahan kurang dari 2 hari sebelum dihapus.
- Kasus B: Throughput Rendah Laju data sangat lambat, hanya 500 MB per hari. Setelah 7 hari, total data yang terkumpul hanya 3.5 GB. Meskipun batas ukuran 5 GB belum tercapai, karena usia pesan pada segmen tertua sudah melewati batas 7 hari, Kafka akan langsung menghapus segmen tersebut.
Prinsip ganda ini memberikan perlindungan berlapis: mengamankan kapasitas disk dari kelebihan muatan (overload) saat lonjakan data, sekaligus menjamin data lama yang tidak terpakai dibersihkan tepat waktu untuk kepatuhan tata kelola data.
Anatomi Evaluasi Penghapusan Segmen Berbasis Ukuran #
Untuk memahami bagaimana Kafka mengevaluasi pemotongan berkas log, kita harus melihat bagaimana ukuran segmen diakumulasikan. Mari kita gambarkan struktur direktori partisi fisik di disk broker:
flowchart TD
subgraph Partisi_Disk ["Folder Partisi Fisik: orders-0/"]
direction LR
S1["00000000.log <br> (Segmen Inaktif 1) <br> Ukuran: 1 GB <br> Status: Dihapus"]
S2["00005000.log <br> (Segmen Inaktif 2) <br> Ukuran: 1 GB <br> Status: Aman"]
S3["00010000.log <br> (Segmen Inaktif 3) <br> Ukuran: 1 GB <br> Status: Aman"]
S4["00015000.log <br> (Segmen Aktif) <br> Ukuran: 800 MB <br> Status: Kebal"]
end
subgraph Evaluasi ["Logika Evaluasi Retensi Ukuran"]
direction TB
Limit["Batas log.retention.bytes = 2.5 GB"]
Sum["Total Ukuran Partisi = 3.8 GB"]
end
S1 -->|"Dipotong oleh Log Cleaner"| Trash["Bebaskan Ruang Disk OS"]
style S1 stroke:#c62828,stroke-width:2px
style S2 stroke:#2e7d32,stroke-width:2px
style S3 stroke:#2e7d32,stroke-width:2px
style S4 stroke:#0288d1,stroke-width:2px
Langkah Evaluasi Pemotongan Log oleh Broker #
- Pengecualian Segmen Aktif: Sama seperti retensi berbasis waktu, berkas segmen aktif (
00015000.logpada diagram di atas) tidak akan pernah dihapus, terlepas dari berapa pun ukurannya. - Kalkulasi Total Ukuran: Broker menghitung jumlah total ukuran berkas segmen (baik aktif maupun tidak aktif) pada folder partisi tersebut. Dari diagram:
$$\text{Total Ukuran} = 1 \text{ GB} + 1 \text{ GB} + 1 \text{ GB} + 0.8 \text{ GB} = 3.8 \text{ GB}$$
- Deteksi Kelebihan Kapasitas: Broker membandingkan hasil kalkulasi dengan batas parameter
log.retention.bytes. Karena total ukuran ($3.8 \text{ GB}$) lebih besar dari batas konfigurasi ($2.5 \text{ GB}$), terjadi pelanggaran batas. - Penghapusan Bertahap: Broker mulai menghapus berkas segmen tidak aktif tertua secara berurutan. Pertama, file
00000000.log(1 GB) beserta file indexnya dihapus dari disk. - Evaluasi Ulang: Broker menghitung kembali total ukuran partisi:
$$\text{Total Ukuran Baru} = 1 \text{ GB} + 1 \text{ GB} + 0.8 \text{ GB} = 2.8 \text{ GB}$$
Karena total ukuran baru ($2.8 \text{ GB}$) masih lebih besar dari batas $2.5 \text{ GB}$, broker akan melanjutkan penghapusan segmen tidak aktif tertua berikutnya pada siklus berikutnya, atau langsung menghapusnya hingga total ukuran benar-benar berada di bawah ambang batas $2.5 \text{ GB}$.
JBOD (Just a Bunch of Disks) & Pengelolaan Penyimpanan Multi-Volume #
Di lingkungan produksi skala enterprise, satu broker Kafka sering kali dikonfigurasi untuk menggunakan beberapa disk fisik secara bersamaan tanpa menggabungkannya lewat arsitektur RAID (JBOD - Just a Bunch of Disks). Hal ini dicapai dengan mendefinisikan beberapa path direktori pada berkas server.properties menggunakan koma sebagai pemisah:
log.dirs=/mnt/disk1/kafka-data,/mnt/disk2/kafka-data,/mnt/disk3/kafka-data
Bagaimana Penentuan Disk Berdampak pada Retensi? #
Ketika kita menggunakan konfigurasi JBOD:
- Penempatan Partisi Baru: Saat partisi baru dibuat, Kafka akan menempatkannya pada disk direktori yang memiliki jumlah partisi paling sedikit, bukan berdasarkan sisa kapasitas disk yang kosong!
- Risiko Disk Asimetris: Jika satu partisi menerima throughput data yang sangat besar, disk tersebut (misal
/mnt/disk1/) bisa penuh jauh lebih cepat daripada disk lainnya, memicu evaluasi retensi ukuran yang lebih sering pada partisi yang menghuninya. - Menggeser Partisi: Kita dapat menggunakan tool CLI
kafka-log-dirs.shuntuk mengevaluasi penggunaan disk di setiap volume. Sejak Kafka 2.0+, kita dapat menggunakan APIalterReplicaLogDirs(melalui program Java atau shell script) untuk memindahkan partisi yang kelebihan beban secara dinamis antar-disk fisik dalam broker yang sama tanpa downtime dan tanpa membebani bandwidth jaringan antar-broker. - Metrik Volume Offline: Kita harus memantau metrik JMX
OfflineLogDirectoryCountuntuk mendeteksi kegagalan salah satu volume disk JBOD kita agar kegagalan disk tunggal tidak melumpuhkan seluruh broker, melainkan hanya menonaktifkan partisi yang bersangkutan.
Menghitung Overhead Memori Fisik: Pre-Allocation File Indeks #
Selain berkas data utama .log, setiap segmen aktif juga disertai oleh file indeks .index dan .timeindex. Ukuran maksimum file indeks ini diatur secara dinamis oleh broker menggunakan parameter:
log.index.size.max.bytes=10485760 # 10 MB (Default)
Jebakan Overhead Alokasi Indeks #
Ketika sebuah segmen baru bertindak sebagai segmen aktif, Kafka akan langsung melakukan pre-allocation fisik sebesar 10 MB penuh untuk file .index dan 10 MB untuk .timeindex di disk OS, terlepas dari apakah data pesan di dalamnya masih kosong.
- Overhead Partisi Kosong: Jika kita memiliki 10.000 partisi aktif pada satu broker, pre-allocation index ini akan secara otomatis memakan ruang disk kosong sebesar:
$$10.000 \text{ partisi} \times 20 \text{ MB (Indeks)} = 200 \text{ GB}$$
Ruang disk 200 GB ini langsung dikonsumsi oleh file-file indeks kosong. Kita wajib memasukkan variabel ini dalam perhitungan kapasitas agar retensi berbasis ukuran tidak terpicu secara prematur akibat berkurangnya ruang disk kosong OS secara drastis.
Mencegah Disk Saturation Menggunakan Quota Produser #
Menerapkan retensi ukuran adalah langkah perlindungan reaktif setelah data masuk ke broker. Langkah preventif yang lebih baik adalah membatasi laju data masuk (ingestion rate) dari sisi produser menggunakan fitur Quotas.
Kita dapat membatasi throughput maksimal yang dapat ditulis oleh produser (misalnya 10 MB/detik per klien) untuk memastikan produser nakal tidak dapat memenuhi disk kluster sebelum Log Cleaner Thread sempat berjalan melakukan tugas penghapusan.
Menyetel Quota Produser dengan CLI #
# Membatasi laju tulis client-id 'payment-app' sebesar 10 MB/s (10485760 bytes/s)
kafka-configs.sh --bootstrap-server localhost:9092 \
--entity-type clients \
--entity-name payment-app \
--alter \
--add-config producer_byte_rate=10485760
Optimasi Filesystem Linux: Pre-Allocation Berkas Segmen #
Ketika Kafka membuat berkas segmen baru di sistem berkas Linux (seperti XFS atau ext4), secara default berkas tersebut dialokasikan secara dinamis seiring bertambahnya data. Namun, di bawah beban kerja throughput tinggi, hal ini dapat menyebabkan fragmentasi berkas fisik pada disk, yang menurunkan performa I/O sequential disk.
Untuk mengatasi hal ini, Kafka menyediakan konfigurasi:
log.preallocate=true
Bagaimana Pre-Allocation Membantu Retensi? #
Ketika properti ini diaktifkan, saat Kafka melakukan rolling segmen baru, broker akan langsung memesan ruang penyimpanan sebesar batas maksimum log.segment.bytes (misalnya 1 GB) secara utuh di disk OS sejak awal, mengisinya dengan byte kosong.
- Manfaat: Sistem operasi menjamin blok data fisik di disk dialokasikan secara berurutan, menghindari fragmentasi.
- Catatan Penting: Fitur ini membuat ukuran fisik file segmen aktif di disk langsung terlihat sebesar 1 GB di OS sejak pertama kali dibuat, meskipun isinya masih kosong. Oleh karena itu, kita harus menyiapkan kapasitas disk cadangan yang matang karena kalkulasi ruang disk akan langsung dikonsumsi secara agresif oleh segmen-segmen aktif baru yang kosong ini.
Rekomendasi Mount Option Filesystem #
Untuk meningkatkan kinerja penulisan dan evaluasi file segmen besar, pastikan mount option pada sistem berkas XFS dikonfigurasi di /etc/fstab dengan:
# Mengoptimalkan mount options untuk sequential write disk data
/dev/sdb1 /var/lib/kafka/data xfs noatime,nodiratime,nobarrier,logbufs=8,logbsize=256k 0 2
Penyetelan noatime dan nodiratime menghilangkan overhead sistem operasi yang harus memperbarui timestamp pembacaan file setiap kali pesan ditarik oleh konsumen.
Kolaborasi Kebijakan Ganda: cleanup.policy=compact,delete
#
Sejak versi Kafka modern, kita dapat menggabungkan dua kebijakan pembersihan log sekaligus pada satu topik yang sama:
cleanup.policy=compact,delete
Cara Kerja Gabungan #
Dalam mode gabungan ini:
- Proses Log Compaction akan berjalan secara berkala untuk memadatkan log segment tidak aktif, menyisakan hanya status data terbaru per kunci (key).
- Di saat yang sama, Size-Based (atau Time-Based) Retention tetap mengevaluasi ukuran total partisi.
- Jika total ukuran partisi terkompresi tersebut masih melebihi batas
log.retention.bytes, maka Kafka akan menghapus segmen terkompresi tertua secara permanen.
Kebijakan ganda ini sangat berguna untuk skenario di mana kita membutuhkan pemadatan status kunci (state) untuk penghematan data harian, namun tetap menuntut pembersihan data historis mutlak jika total data melampaui kapasitas disk fisik kluster yang kita miliki.
Runbook Darurat: Mengatasi Disk Broker Penuh (Disk Saturation) #
Jika terjadi kondisi darurat di mana disk salah satu broker menyentuh angka 95% akibat keterlambatan pembersihan data atau salah perhitungan kapasitas, berikut adalah langkah-langkah mitigasi darurat yang dapat kita jalankan secara aman.
Langkah 1: Identifikasi Topik Terbesar #
Temukan folder partisi mana yang paling banyak memakan ruang disk menggunakan perintah disk Linux:
# Menemukan 10 folder partisi terbesar di path log Kafka
du -h --max-depth=1 /var/lib/kafka/data | sort -hr | head -n 10
Langkah 2: Terapkan Retensi Ukuran Ketat Secara Dinamis #
Jangan mencoba menghapus berkas .log secara manual menggunakan perintah rm Linux! Menghapus file log secara manual akan merusak indeks broker, memicu crash pada proses Java Kafka, dan merusak metadata KRaft/ZooKeeper.
Solusi yang benar adalah memicu Log Cleaner Thread secara paksa dengan menurunkan parameter retensi ukuran topik target secara dinamis ke batas yang sangat rendah (misalnya 2 GB per partisi):
# Menurunkan batas retensi secara agresif untuk memicu pembersihan instan
kafka-configs.sh --bootstrap-server localhost:9092 \
--entity-type topics \
--entity-name nama-topik-raksasa \
--alter \
--add-config log.retention.bytes=2147483648
Dalam waktu maksimal 5 menit (sesuai interval log.retention.check.interval.ms), Log Cleaner Thread akan memindai topik tersebut, mendeteksi pelanggaran ukuran, dan menghapus segmen-segmen usang untuk membebaskan ruang disk secara aman.
Ringkasan #
- Retensi Berbasis Ukuran: Berfungsi melindungi media penyimpanan fisik broker dari kehabisan kapasitas disk total saat terjadi lonjakan data.
- Batas Per Partisi: Properti
log.retention.bytesberlaku untuk satu partisi tunggal, bukan akumulasi total seluruh topik.- JBOD (Multi-Disk): Konfigurasi multi-directory
log.dirsmemungkinkan pembagian beban disk tanpa RAID, namun memerlukan pemantauan kapasitas antar-volume secara detail.- Sinergi Evaluasi: Ketika retensi waktu dan ukuran diaktifkan bersamaan, Kafka menggunakan prinsip “whichever comes first” (siapa cepat dia dapat).
- Pre-Allocation: Penyetelan
log.preallocate=truemembantu mencegah fragmentasi berkas pada sistem berkas Linux dengan memesan kapasitas segmen utuh di awal.- Overhead Indeks: Setiap segmen aktif pre-allocates file
.indexdan.timeindexmasing-masing 10 MB di disk, menghasilkan overhead disk untuk partisi dalam jumlah besar.- Quotas: Gunakan parameter
producer_byte_rateuntuk menahan laju produser nakal secara preventif dari pemenuhan disk space.- Gabungan Kebijakan: Penyetelan
cleanup.policy=compact,deletememadatkan data kunci sekaligus membatasi ukuran penyimpanan fisik partisi secara absolut.