Episode ini membahas producer Kafka: struktur ProducerRecord, konfigurasi dasar, pola pengiriman fire-and-forget, synchronous, dan asynchronous dengan callback, batching, tuning acks, retries, compression, hingga idempotent producer untuk mencegah duplikasi.

Producer adalah sisi tulis Kafka — aplikasi yang mengubah fakta bisnis menjadi event yang dikirim ke topic. Meskipun terlihat sederhana, producer menyimpan banyak keputusan penting: berapa lama menunggu konfirmasi broker (acks), berapa banyak retry, seberapa besar batch, dan apakah data akan terkirim duplikat atau tidak.
Episode 5 ini akan membawa kalian dari nol hingga mahir menulis producer: memahami struktur ProducerRecord, API producer di empat bahasa populer, pola pengiriman fire-and-forget, synchronous dan asynchronous dengan callback, serta tuning parameter yang menentukan throughput dan durability.
Di akhir episode, kalian akan memahami idempotent producer — kunci menuju exactly-once semantics yang akan kita perdalam di episode 8 dan 9.
Setiap producer membutuhkan minimal bootstrap.servers=localhost:9092 — daftar broker awal untuk menemukan cluster. Parameter penting lainnya termasuk key.serializer dan value.serializer yang mengubah objek menjadi byte:
bootstrap.servers=localhost:9092
key.serializer=org.apache.kafka.common.serialization.StringSerializer
value.serializer=org.apache.kafka.common.serialization.StringSerializer
acks=allUnit pengiriman adalah ProducerRecord yang berisi topic, partition opsional, key, value, timestamp, dan headers. Jika partition tidak diberikan, partitioner menentukan tujuan berdasarkan key; jika key juga kosong, record disebar secara round-robin atau sticky.
Mengirim record ke Kafka bersifat asinkron secara internal: producer menempatkan record ke buffer, lalu mengirim batch ke broker di latar belakang. send() mengembalikan future yang bisa di-blok (get()) untuk perilaku sinkron, atau dilengkapi callback untuk menerima hasil tanpa blok.
Java adalah bahasa asli Kafka. Contoh minimal:
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
try (Producer<String, String> producer = new KafkaProducer<>(props)) {
producer.send(new ProducerRecord<>("orders", "order-001", "created"));
}Pola try-with-resources memastikan producer di-close, membuang buffer tersisa sebelum keluar.
Ekosistem utama di luar Java:
confluent-kafka (binding librdkafka) atau kafka-python.confluent-kafka-go atau sarama dari Shopify.kafkajs, library populer dengan API modern berbasis promise.from confluent_kafka import Producer
p = Producer({"bootstrap.servers": "localhost:9092"})
p.produce("orders", key="order-001", value="created")
p.flush()Semua library mengikuti model yang sama: konfigurasi, kirim, dan flush/poll untuk memastikan batch terkirim.
Pola paling sederhana: panggil send() tanpa peduli hasilnya. Cocok untuk data yang boleh hilang jika broker bermasalah, tetapi biasanya kurang bijak karena error seperti topic tidak ada akan diam-diam terlewat.
Blok hingga broker merespon. Paling aman untuk correctness, tetapi mengorbankan throughput karena setiap pengiriman menunggu round-trip:
producer.send(record).get();Pola terbaik untuk throughput dan kesadaran error: send() tidak memblokir, dan callback dijalankan saat hasil tiba:
producer.send(record, (metadata, exception) -> {
if (exception != null) {
System.err.println("Gagal mengirim: " + exception.getMessage());
} else {
System.out.println("OK ke partition " + metadata.partition());
}
});Alih-alih mengirim satu per satu, producer mengumpulkan record dalam batch. Dua parameter menentukan batching: batch.size (maksimum byte per batch, default 16KB) dan linger.ms (berapa lama menahan sebelum mengirim, default 0). Menaikkan linger.ms=20 sering meningkatkan throughput drastis dengan tambahan latensi kecil.
acks menentukan tingkat konfirmasi:
acks=0: tanpa konfirmasi, tercepat, rawan kehilangan.acks=1: leader menulis ke log lokal, tanpa menunggu follower.acks=all (atau -1): semua ISR mengkonfirmasi, durability tertinggi.retries mengontrol berapa kali pengiriman gagal dicoba lagi, dan retry.backoff.ms jeda antar percobaan. Dengan acks=all dan idempotence, retry aman dari duplikasi.
max.in.flight.requests.per.connection membatasi berapa banyak request yang belum dikonfirmasi. Nilai lebih dari 1 dapat menciptakan reordering jika terjadi retry, kecuali idempotence aktif. compression.type (gzip, snappy, lz4, zstd) mengompresi payload: zstd menawarkan rasio terbaik, cocok untuk payload besar.
batch.size=65536
linger.ms=20
compression.type=zstd
max.in.flight.requests.per.connection=5
buffer.memory=33554432buffer.memory membatasi total memori producer untuk record yang menunggu dikirim; jika penuh, send() akan memblokir sampai ada ruang.
Tanpa perlindungan, retry dapat mengirim record dua kali jika konfirmasi pertama hilang. Idempotent producer menghilangkan duplikasi ini dengan memberi nomor sekuens per partition dan ID producer:
enable.idempotence=true
acks=all
max.in.flight.requests.per.connection=5Saat enable.idempotence=true, broker secara otomatis memaksa acks=all dan retries besar. Kombinasi ini menjamin tidak ada duplikasi dan tidak ada reordering per partition — dasarnya exactly-once untuk tulis.
Untuk atomicity lintas partition dan stream processing end-to-end, gunakan transactional producer dengan transactional.id. Nilai ini harus unik dan stabil per instance. Detail lengkap akan dibahas di episode 9:
transactional.id=order-svc-1
transaction.timeout.ms=60000Warning
Idempotence mencegah duplikasi karena retry, tetapi tidak membuat operasi aplikasi atomic. Jika aplikasi crash antara menulis database dan mengirim event, event bisa hilang — masalah ini diselesaikan dengan pola transactional outbox di episode 26.
Di episode 5 ini kalian sudah menulis producer di empat bahasa, memahami struktur ProducerRecord, tiga pola pengiriman (fire-and-forget, synchronous, asynchronous dengan callback), teknik batching, dan tuning acks, retries, max.in.flight.requests, compression.type, batch.size, serta linger.ms. Terakhir, kalian mengenal idempotent producer sebagai langkah pertama menuju exactly-once.
Inti yang harus dibawa pulang:
ProducerRecord berisi topic, key, value, timestamp, dan headers.acks=all memberi durability tertinggi; acks=0 tercepat tapi rawan kehilangan data.linger.ms dan batch.size meningkatkan throughput signifikan.compression.type=zstd cocok untuk payload besar.enable.idempotence=true mencegah duplikasi dan reordering saat retry.Di episode 6 selanjutnya kita membalik arah: consumers — cara membaca data dari Kafka. Kalian akan belajar subscription, polling, consumer group dan rebalancing, pengelolaan offset dengan commit manual dan auto-commit, tuning fetch.min.bytes, max.poll.records, serta pola consumer yang benar agar tidak tersendat. Siapkan kode consumer pertama kalian!