Simulasi antrean pada chapter sebelumnya hidup hanya di satu proses Python: begitu proses berhenti, seluruh isi antrean ikut hilang, dan hanya ada satu producer dengan satu consumer. Kebutuhan nyata TokoKita jauh lebih besar — ratusan layanan menulis event, pipeline berjalan di banyak mesin, dan pesan harus bertahan berhari-hari agar sistem baru bisa membaca ulang. Apache Kafka adalah platform streaming terdistribusi yang dirancang untuk skala tersebut: log peristiwa yang direplikasi lintas mesin dan disimpan di disk. Chapter ini memperkenalkan arsitektur Kafka 4.x, cara menjalankannya lewat Docker, dan klien Python-nya.
Apa Itu Apache Kafka #
Kafka menyimpan event dalam topic, dan setiap topic dipecah menjadi partition berbentuk append-only log: baris baru selalu ditambah di ekor, baris lama tidak pernah diubah. Tiga konsekuensi penting mengikuti bentuk tersebut. Pertama, penyimpanan berbasis disk membuat kapasitas antrean tidak lagi dibatasi memori satu mesin. Kedua, pesan tidak dihapus setelah dibaca — Kafka menyimpan pesan selama retention (misalnya tujuh hari), sehingga consumer baru atau consumer yang membaca ulang tetap menemukan data lama. Ketiga, karena data bertahan, satu topic bisa melayani banyak consumer dengan kecepatan berbeda tanpa saling mengganggu.
Kafka berjalan sebagai cluster berisi beberapa mesin bernama broker. Setiap broker menampung sebagian partition topic, dan setiap partition direplikasi ke broker lain — mekanisme yang identik dengan konsep Replication pada section distributed systems. Ketika satu broker berhenti, partition yang direplikasi tetap tersedia di broker lain.
KRaft: Kafka Tanpa ZooKeeper #
Cluster Kafka butuh penyimpan metadata bersama — daftar broker, topic, konfigurasi, dan pemimpin tiap partition. Versi lama menitipkan metadata tersebut pada ZooKeeper, layanan koordinasi terpisah; sejak versi 4.0 ZooKeeper dihapus dan seluruh metadata berpindah ke internal topic __cluster_metadata yang dikelola Kafka sendiri lewat protokol KRaft.
Cara tercepat menghadirkan Kafka di laptop adalah image Docker resmi apache/kafka, yang langsung berjalan dalam mode KRaft gabungan:
services:
kafka:
image: apache/kafka:latest
container_name: tokokita-kafka
ports:
- "9092:9092"Struktur YAML di atas kita verifikasi terurai dengan benar memakai PyYAML — eksekusi nyata, bukan sekadar periksa mata:
"""Verifikasi struktur docker-compose Kafka KRaft dengan PyYAML."""
import yaml
with open("docker-compose.yaml", encoding="utf-8") as f:
doc = yaml.safe_load(f)
kafka = doc["services"]["kafka"]
print("image :", kafka["image"])
print("ports :", kafka["ports"])
print("valid : struktur YAML terurai tanpa galat")Output yang Dihasilkan:
image : apache/kafka:latest
ports : ['9092:9092']
valid : struktur YAML terurai tanpa galatSetelah docker compose up -d, broker siap menerima koneksi di localhost:9092 tanpa konfigurasi tambahan. Detail image dan opsi konfigurasinya terdokumentasi di dokumentasi Docker
.
Klien Kafka untuk TokoKita #
Klien Python paling umum adalah pustaka kafka-python. Kode berikut menuntaskan siklus lengkap TokoKita: membuat topic, mengirim tiga pesanan berkunci, lalu membacanya sebagai consumer group:
"""Klien Kafka untuk TokoKita: buat topic, kirim event berkunci, lalu baca
sebagai consumer group. Kafka tidak dijalankan di lingkungan penulisan —
kode ini diverifikasi sintaks dengan py_compile dan mengikuti API
kafka-python 2.x terhadap broker Kafka 4.x."""
import json
from kafka import KafkaAdminClient, KafkaConsumer, KafkaProducer
from kafka.admin import NewTopic
from kafka.errors import TopicAlreadyExistsError
BOOTSTRAP = "localhost:9092"
TOPIC = "tokokita.orders"
def buat_topic():
"""Buat topic 3 partition; idempotent karena error duplikat diabaikan."""
admin = KafkaAdminClient(bootstrap_servers=BOOTSTRAP)
try:
admin.create_topics(
[NewTopic(name=TOPIC, num_partitions=3, replication_factor=1)]
)
except TopicAlreadyExistsError:
pass # topic sudah ada dari eksekusi sebelumnya
finally:
admin.close()
def kirim_pesanan():
"""Producer: kunci = nama pelanggan agar urutannya menempel satu partition."""
producer = KafkaProducer(
bootstrap_servers=BOOTSTRAP,
value_serializer=lambda v: json.dumps(v).encode("utf-8"),
)
for order_id, pelanggan, total in [
("ORD-2001", "budi", 257_000),
("ORD-2002", "siti", 89_000),
("ORD-2003", "dewi", 512_000),
]:
hasil = producer.send(
TOPIC,
key=pelanggan.encode("utf-8"),
value={"order_id": order_id, "total": total},
)
hasil.get(timeout=10) # tunggu ack broker sebelum kirim berikutnya
producer.flush()
producer.close()
def baca_pesanan():
"""Consumer group analitik: mulai dari offset paling awal sekali saja."""
consumer = KafkaConsumer(
TOPIC,
bootstrap_servers=BOOTSTRAP,
group_id="analitik",
auto_offset_reset="earliest",
)
for pesan in consumer:
print(f"{pesan.topic}[p{pesan.partition}] offset={pesan.offset} "
f"kunci={pesan.key.decode()} nilai={pesan.value.decode()}")
if pesan.offset >= 2: # cukup tiga event untuk demonstrasi
break
consumer.close()
if __name__ == "__main__":
buat_topic()
kirim_pesanan()
baca_pesanan()Broker Kafka tidak dijalankan pada lingkungan penulisan chapter ini, sehingga kode di atas diverifikasi sintaks dengan py_compile dan tidak disertai blok output eksekusi. Perilakunya saat broker hidup, sesuai dokumentasi resmi: buat_topic mengirim permintaan ke broker dan mengabaikan TopicAlreadyExistsError agar aman dijalankan berulang; kirim_pesanan menyerahkan tiap event dengan kunci pelanggan — kunci menentukan partition tujuan, jadi seluruh pesanan Budi menempel pada partition yang sama; hasil.get(timeout=10) menunggu ack broker sebagai bukti event sudah tersimpan. Pada sisi pembaca, group_id="analitik" mendaftarkan consumer ke sebuah consumer group, auto_offset_reset="earliest" membuat pembacaan pertama mulai dari pesan paling awal, dan consumer.close() mengirim posisi baca terakhir (committed offset) sebelum keluar dengan rapi.
Mengapa Kafka untuk Skala TokoKita #
- Throughput — penulisan sequential ke disk plus batching menjadikan throughput jutaan event per detik realistis pada perangkat keras biasa.
- Ketahanan — replikasi partition ke beberapa broker plus retensi berbasis waktu menjaga data tetap ada melewati kegagalan mesin.
- Replay — consumer dapat mengatur ulang offset untuk membaca ulang histori event, sesuatu yang tidak dimiliki antrean klasik.
- Decoupling — consumer group memungkinkan tim analitik, tim notifikasi, dan tim stok membaca topic yang sama tanpa saling menunggu.
Rujukan lengkap konfigurasi dan semantik operasionalnya ada di dokumentasi Apache Kafka . Seluruh keunggulan tersebut bertumpu pada tiga kata kunci yang selama ini kita sebut sepintas — topic, partition, offset. Ketiganya akhirnya kita bedah satu per satu pada Chapter Topics, Partitions, dan Offsets.