Pustaka, Bukan Infrastruktur Baru
Berbeda dari Flink atau Spark yang menuntut klaster tersendiri, Kafka Streams adalah dependensi biasa di dalam aplikasi Anda. Skala dilakukan dengan menjalankan lebih banyak instans — persis seperti menskalakan layanan HTTP.
Aplikasi Anda (JAR / kontainer) ├── Kafka Streams sebagai pustaka ├── RocksDB untuk state lokal └── Kafka untuk masukan, keluaran, dan cadangan state
Stream dan Table
| Abstraksi | Artinya | Contoh |
|---|---|---|
KStream | Aliran peristiwa; tiap catatan berdiri sendiri | "pesanan-123 dibuat" |
KTable | Keadaan terkini per kunci; catatan baru menimpa yang lama | "status pesanan-123 = dibayar" |
GlobalKTable | Salinan penuh tabel di tiap instans | Tabel referensi kecil, misalnya daftar mata uang |
Keduanya adalah dua cara memandang data yang sama. Menjumlahkan seluruh peristiwa perubahan menghasilkan keadaan terkini (stream ke table), dan mencatat tiap perubahan keadaan menghasilkan aliran peristiwa (table ke stream). Memahami dualitas ini membuat sebagian besar API Kafka Streams terasa wajar.
State Store dan Changelog
Operasi stateful — agregasi, join, penghitungan berjendela — menyimpan data di RocksDB pada disk lokal instans. Agar tahan terhadap kegagalan, tiap perubahan state juga ditulis ke topik changelog di Kafka yang bersifat compacted.
Instans mati → pod baru dijadwalkan ↳ baca ulang topik changelog ↳ bangun kembali RocksDB lokal ↳ lanjutkan dari titik terakhir
State store berukuran puluhan gigabyte membutuhkan waktu lama untuk dibangun ulang dari changelog, dan selama itu partisi terkait tidak diproses. Mitigasinya: standby replica (num.standby.replicas) yang menjaga salinan hangat, dan volume persisten di Kubernetes agar RocksDB tidak hilang saat pod dijadwalkan ulang.
Windowing
| Jenis | Perilaku | Contoh pemakaian |
|---|---|---|
| Tumbling | Jendela tetap, tidak tumpang tindih | Jumlah pesanan per 5 menit |
| Hopping | Jendela tetap yang saling tumpang tindih | Rata-rata 10 menit, diperbarui tiap menit |
| Sliding | Berbasis selisih waktu antar catatan | Deteksi lonjakan |
| Session | Dipisahkan oleh periode tidak aktif | Sesi aktivitas pengguna |
Kafka Streams default memakai waktu kejadian yang tertanam pada catatan, bukan waktu pemrosesan. Peristiwa yang datang terlambat — dari perangkat seluler yang sempat offline, misalnya — akan jatuh ke jendela masa lalu. Bila jendela itu sudah ditutup melebihi grace period, peristiwa tersebut dibuang tanpa peringatan. Setel grace period sesuai keterlambatan yang realistis di sistem Anda, dan pantau metrik catatan yang terlambat.
Contoh Topologi
StreamsBuilder pembangun = new StreamsBuilder();
KStream<String, Pesanan> pesanan = pembangun.stream("pesanan");
KTable<String, Pelanggan> pelanggan = pembangun.table("pelanggan");
pesanan
.filter((k, p) -> p.getTotal() > 1_000_000)
.join(pelanggan, (p, c) -> perkaya(p, c))
.groupBy((k, p) -> p.getWilayah())
.windowedBy(TimeWindows.ofSizeAndGrace(
Duration.ofMinutes(5), Duration.ofMinutes(2)))
.count()
.toStream()
.to("pesanan-besar-per-wilayah");
Menambah atau memindahkan operator stateful mengubah nama internal topik changelog dan repartition. Rilis yang tampak kecil bisa membuat aplikasi kehilangan seluruh state-nya. Beri nama eksplisit pada state store dan operator penting, dan uji jalur peningkatan versi sebelum menerapkannya di produksi.
Kafka Streams atau Flink?
| Pilih Kafka Streams bila | Pilih Flink bila |
|---|---|
| Sumber dan tujuan sama-sama Kafka | Perlu banyak sumber dan sink beragam |
| Tim ingin menjalankannya seperti layanan biasa | Sudah ada tim data yang mengelola klaster |
| Tidak ingin menambah infrastruktur baru | Butuh SQL, batch, dan streaming dalam satu mesin |
| Skala menengah | Skala sangat besar dengan state raksasa |