Apache Kafka untuk Data Engineer: Panduan Lengkap Partisi, Consumer Group, dan Pipeline Streaming
Panduan komprehensif Apache Kafka untuk data engineering: arsitektur partisi, consumer group, mode KRaft tanpa ZooKeeper, CDC dengan Debezium, exactly-once semantics, dan Share Groups di Kafka 4.x. Dilengkapi contoh kode Python dan konfigurasi Docker Compose.

Apache Kafka telah menjadi tulang punggung arsitektur data real-time di berbagai industri. Mulai dari pipeline ingestion berskala besar, Change Data Capture, hingga pemrosesan event streaming yang menangani jutaan pesan per detik, penguasaan Kafka merupakan keterampilan wajib bagi setiap profesional di bidang data engineering. Artikel ini membahas konsep fundamental, pola implementasi yang paling sering digunakan di lingkungan produksi, serta fitur terbaru Kafka 4.x termasuk mode KRaft dan Share Groups.
Arsitektur internal Kafka, strategi partisi, consumer group dengan manajemen offset manual, CDC menggunakan Debezium, exactly-once semantics melalui transaksi, Share Groups di Kafka 4.x, serta pertanyaan wawancara yang sering muncul untuk posisi data engineer.
Arsitektur Kafka: Broker, Topic, dan Partisi
Kafka beroperasi sebagai distributed log yang bersifat immutable. Producer menulis record ke dalam topic, setiap topic dibagi menjadi beberapa partisi, dan setiap partisi direplikasi ke beberapa broker. Model ini memberikan tiga properti krusial untuk pipeline data: urutan yang terjamin di dalam setiap partisi, retensi data yang dapat dikonfigurasi, serta skalabilitas horizontal.
Kluster produksi pada umumnya menjalankan antara 3 hingga 30 broker, tergantung pada volume data dan persyaratan latensi. Setiap broker menyimpan segmen partisi pada disk dan memanfaatkan page cache kernel untuk mencapai pembacaan sekuensial yang sangat cepat. Pola ini, yang dikenal sebagai zero-copy, memungkinkan Kafka mencapai throughput lebih dari 1 GB/s per broker pada perangkat keras modern.
Hubungan antara partisi dan paralelisme bersifat langsung: jumlah partisi pada sebuah topic menentukan jumlah maksimum consumer yang dapat memproses data secara bersamaan dalam satu consumer group. Apabila sebuah topic memiliki 6 partisi, maka dapat dijalankan hingga 6 consumer secara paralel. Menambahkan consumer melebihi jumlah partisi hanya akan menghasilkan consumer yang menganggur tanpa menerima data apa pun.
Kafka 4.x dan Mode KRaft: Berakhirnya Era ZooKeeper
Kafka 4.0, yang dirilis pada Maret 2025, secara resmi menghapus ketergantungan terhadap ZooKeeper. Mode KRaft (Kafka Raft) mengelola metadata kluster langsung di dalam broker menggunakan protokol konsensus berbasis Raft. Penyederhanaan arsitektur ini mengurangi jumlah komponen yang perlu dipantau, mempercepat pemulihan dari kegagalan, dan memungkinkan penskalaan hingga jutaan partisi per kluster.
Bagi para data engineer, penghapusan ZooKeeper berarti satu hal konkret: deployment yang jauh lebih sederhana. Sebuah kluster pengembangan lokal dapat dijalankan hanya dengan satu file Docker Compose.
# docker-compose.yml — Kafka 4.x KRaft cluster (no ZooKeeper)
services:
kafka-1:
image: apache/kafka:4.2.0
environment:
KAFKA_NODE_ID: 1
KAFKA_PROCESS_ROLES: broker,controller
KAFKA_CONTROLLER_QUORUM_VOTERS: 1@kafka-1:9093,2@kafka-2:9093,3@kafka-3:9093
KAFKA_LISTENERS: PLAINTEXT://:9092,CONTROLLER://:9093
KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
KAFKA_LOG_DIRS: /var/lib/kafka/data
KAFKA_NUM_PARTITIONS: 6
KAFKA_DEFAULT_REPLICATION_FACTOR: 3
KAFKA_MIN_INSYNC_REPLICAS: 2
ports:
- "9092:9092"Parameter KAFKA_PROCESS_ROLES: broker,controller menunjukkan bahwa setiap node menjalankan kedua peran sekaligus. Di lingkungan produksi, pemisahan peran controller dan broker ke node yang berbeda merupakan praktik umum untuk mengisolasi beban pengelolaan metadata dari pemrosesan pesan.
replication_factor sebesar 3 dengan min.insync.replicas sebesar 2 menjamin bahwa setiap pesan yang dikonfirmasi dengan acks=all tetap bertahan meskipun satu broker mengalami kegagalan. Konfigurasi ini memberikan keseimbangan yang baik antara durabilitas dan ketersediaan untuk sebagian besar pipeline data.
Strategi Partisi untuk Pipeline Data
Pemilihan partition key menentukan urutan pesan, distribusi beban, dan kemampuan penskalaan consumer. Memilih key yang tidak tepat dapat menghasilkan hot partition yang memusatkan beban pada satu consumer, sementara consumer lainnya tidak mendapatkan data sama sekali.
Terdapat tiga strategi utama untuk memilih partition key dalam konteks data engineering:
Partisi berdasarkan entitas bisnis: Menggunakan identifier entitas utama (customer_id, account_id) sebagai key. Semua event dari satu pelanggan diarahkan ke partisi yang sama, sehingga urutan temporal terjaga. Strategi ini paling umum digunakan untuk pipeline pesanan, transaksi, dan aktivitas pengguna.
Partisi berdasarkan sesi: Untuk data clickstream atau telemetri, key session_id mengelompokkan semua event dalam satu sesi ke partisi yang sama. Menggunakan user_id tidak tepat apabila seorang pengguna dapat memiliki beberapa sesi secara bersamaan, karena urutan di dalam masing-masing sesi akan hilang.
Partisi round-robin: Ketika urutan tidak diperlukan (log, metrik umum), menghilangkan key akan mendistribusikan pesan secara merata. Opsi ini memaksimalkan paralelisme dengan mengorbankan jaminan urutan.
# partition_strategy.py — Choosing the right partition key
from confluent_kafka import Producer
import json
def create_producer():
return Producer({
'bootstrap.servers': 'kafka-1:9092',
'acks': 'all',
'enable.idempotence': True,
'max.in.flight.requests.per.connection': 5
})
def publish_order_event(producer, event):
# Key by customer_id: all events for one customer stay ordered
key = str(event['customer_id']).encode('utf-8')
value = json.dumps(event).encode('utf-8')
producer.produce(
topic='order-events',
key=key,
value=value,
headers=[('source', b'order-service'), ('version', b'2')]
)
producer.flush()
def publish_clickstream(producer, event):
# Key by session_id: ordering within a session matters
# NOT by user_id — one user may have multiple sessions
key = str(event['session_id']).encode('utf-8')
value = json.dumps(event).encode('utf-8')
producer.produce(
topic='clickstream',
key=key,
value=value
)Konfigurasi enable.idempotence: True bersama dengan acks: all mengaktifkan produksi idempoten, mencegah duplikasi ketika producer melakukan retry akibat timeout jaringan. Kombinasi dengan max.in.flight.requests.per.connection: 5 tetap menjaga urutan pesan meskipun terdapat retry aktif, sebuah perbaikan yang diperkenalkan sejak Kafka 2.0 yang menghilangkan batasan sebelumnya untuk membatasi request in-flight menjadi hanya 1.
Apabila sebuah partition key terlalu terkonsentrasi (misalnya, 80% event berasal dari satu customer_id saja), partisi tersebut akan menerima beban yang tidak proporsional. Sangat penting untuk memantau lag per partisi dan, apabila diperlukan, mempertimbangkan penggunaan key komposit (customer_id + tanggal) atau melakukan repartisi.
Consumer Group dan Manajemen Offset Manual
Consumer group merupakan mekanisme fundamental untuk paralelisme di Kafka. Setiap consumer dalam sebuah group menerima subset partisi secara eksklusif. Ketika sebuah consumer mengalami kegagalan atau consumer baru bergabung, Kafka melakukan rebalancing yang mendistribusikan ulang partisi di antara anggota group yang aktif.
Untuk pipeline data, pola yang direkomendasikan adalah menonaktifkan auto-commit offset dan melakukan commit secara manual setelah memproses setiap batch. Pendekatan ini menjamin semantik at-least-once: apabila consumer gagal sebelum melakukan commit, pesan-pesan tersebut akan diproses ulang saat restart. Konsekuensinya, logika pemrosesan harus bersifat idempoten untuk menangani duplikasi dengan benar.
Pemrosesan dalam micro-batch meningkatkan throughput secara signifikan dengan mengamortisasi operasi penulisan ke warehouse. Alih-alih menulis satu record per satu record, pesan dikumpulkan dalam buffer dan satu operasi penulisan dieksekusi per batch.
# consumer_pipeline.py — Consumer group with manual offset management
from confluent_kafka import Consumer, KafkaError
import json
def create_consumer(group_id: str):
return Consumer({
'bootstrap.servers': 'kafka-1:9092',
'group.id': group_id,
'auto.offset.reset': 'earliest',
'enable.auto.commit': False, # Manual commit for at-least-once
'max.poll.interval.ms': 300000,
'session.timeout.ms': 45000,
'isolation.level': 'read_committed' # Only read committed transactions
})
def process_batch(consumer: Consumer, batch_size: int = 500):
"""Process records in micro-batches for throughput."""
consumer.subscribe(['order-events'])
buffer = []
while True:
msg = consumer.poll(timeout=1.0)
if msg is None:
continue
if msg.error():
if msg.error().code() == KafkaError._PARTITION_EOF:
continue
raise Exception(msg.error())
record = json.loads(msg.value().decode('utf-8'))
buffer.append(record)
if len(buffer) >= batch_size:
# Process the full batch (write to warehouse, etc.)
write_to_warehouse(buffer)
# Commit AFTER successful processing
consumer.commit(asynchronous=False)
buffer.clear()
def write_to_warehouse(records: list):
# Insert batch into data warehouse (BigQuery, Snowflake, etc.)
passParameter isolation.level: read_committed sangat penting ketika producer menggunakan transaksi. Dengan konfigurasi ini, consumer hanya membaca pesan yang telah dikonfirmasi oleh transaksi yang berhasil, sehingga menghindari pemrosesan data dari transaksi yang dibatalkan.
Konfigurasi max.poll.interval.ms: 300000 (5 menit) menentukan waktu maksimum antara pemanggilan poll(). Apabila pemrosesan sebuah batch memerlukan waktu lebih lama dari interval ini, Kafka menganggap consumer tersebut sudah tidak aktif dan memicu rebalancing. Untuk batch berukuran besar yang ditulis ke warehouse dengan latensi tinggi, nilai ini perlu disesuaikan.
Siap menguasai wawancara Data Engineering Anda?
Berlatih dengan simulator interaktif, flashcards, dan tes teknis kami.
Change Data Capture dengan Debezium dan Kafka Connect
Change Data Capture (CDC) menangkap perubahan pada level baris di database sumber dan mempublikasikannya sebagai event ke topic Kafka. Pola ini menghilangkan kebutuhan ETL batch untuk menyinkronkan database operasional dengan data warehouse analitis.
Debezium, konektor CDC yang menjadi standar de facto untuk Kafka Connect, membaca log replikasi PostgreSQL (WAL), MySQL (binlog), atau MongoDB (oplog) dan mengubah setiap INSERT, UPDATE, dan DELETE menjadi event terstruktur. Konektor ini mempertahankan posisinya di dalam log, menjamin bahwa tidak ada perubahan yang terlewat meskipun terjadi restart.
Konfigurasi konektor CDC untuk PostgreSQL mengilustrasikan komponen-komponen kunci dalam pipeline:
{
"name": "postgres-cdc-source",
"config": {
"connector.class": "io.debezium.connector.postgresql.PostgresConnector",
"database.hostname": "postgres-primary",
"database.port": "5432",
"database.user": "replication_user",
"database.dbname": "production",
"topic.prefix": "cdc",
"table.include.list": "public.orders,public.customers,public.products",
"slot.name": "debezium_slot",
"plugin.name": "pgoutput",
"publication.name": "dbz_publication",
"snapshot.mode": "initial",
"transforms": "route",
"transforms.route.type": "org.apache.kafka.connect.transforms.RegexRouter",
"transforms.route.regex": "cdc\\.public\\.(.*)",
"transforms.route.replacement": "warehouse.$1"
}
}Field snapshot.mode: initial menunjukkan bahwa Debezium terlebih dahulu mengambil snapshot lengkap dari tabel-tabel yang dikonfigurasi, kemudian beralih ke streaming perubahan inkremental. Transform RegexRouter mengubah nama topic dari cdc.public.orders menjadi warehouse.orders, memudahkan pengorganisasian topic berdasarkan tujuan.
Replication slot (debezium_slot) memastikan PostgreSQL tidak menghapus segmen WAL yang belum dikonsumsi. Sangat penting untuk memantau ukuran slot: apabila konektor berhenti selama berjam-jam, slot dapat mengakumulasi gigabyte WAL yang berdampak pada ruang disk server database.
Apabila Debezium berhenti atau terputus dalam waktu yang lama, replication slot akan mengakumulasi segmen WAL yang belum diproses. Disarankan untuk mengonfigurasi alert terhadap ukuran slot dan menetapkan batas retensi maksimum di PostgreSQL (max_slot_wal_keep_size).
Exactly-Once Semantics: Transaksi di Kafka
Semantik exactly-once menjamin bahwa setiap pesan diproses tepat satu kali, bahkan ketika terjadi kegagalan jaringan atau restart consumer. Kafka mengimplementasikan exactly-once melalui transaksi yang membungkus siklus lengkap consume-transform-produce dalam satu operasi atomik.
Pola transaksional bekerja sebagai berikut: consumer membaca sebuah pesan, mentransformasikannya, dan mempublikasikan hasilnya ke topic output. Offset consumer dan pesan yang diproduksi dikonfirmasi dalam transaksi yang sama. Apabila salah satu langkah gagal, seluruh transaksi dibatalkan dan consumer memproses ulang pesan tersebut pada siklus berikutnya.
# exactly_once_pipeline.py — Transactional consume-transform-produce
from confluent_kafka import Consumer, Producer
import json
def transactional_pipeline():
consumer = Consumer({
'bootstrap.servers': 'kafka-1:9092',
'group.id': 'etl-transformer',
'enable.auto.commit': False,
'isolation.level': 'read_committed'
})
producer = Producer({
'bootstrap.servers': 'kafka-1:9092',
'transactional.id': 'etl-transformer-001',
'acks': 'all',
'enable.idempotence': True
})
producer.init_transactions()
consumer.subscribe(['raw-events'])
while True:
msg = consumer.poll(1.0)
if msg is None or msg.error():
continue
# Begin atomic transaction
producer.begin_transaction()
try:
raw = json.loads(msg.value())
enriched = transform(raw)
# Write transformed record to output topic
producer.produce(
'enriched-events',
key=msg.key(),
value=json.dumps(enriched).encode('utf-8')
)
# Commit consumer offset within the same transaction
producer.send_offsets_to_transaction(
consumer.position(consumer.assignment()),
consumer.consumer_group_metadata()
)
producer.commit_transaction()
except Exception:
producer.abort_transaction()
def transform(record: dict) -> dict:
# Apply business logic transformations
record['processed_at'] = '2026-04-20T00:00:00Z'
record['pipeline_version'] = '2.1'
return recordtransactional.id mengidentifikasi producer transaksional secara unik. Apabila producer di-restart dengan ID yang sama, Kafka secara otomatis membatalkan transaksi yang masih tertunda dari producer sebelumnya, mencegah pesan yang duplikat atau orphan. Setiap instance pipeline harus memiliki ID transaksional yang berbeda.
Exactly-once menambahkan penalti latensi yang terukur (antara 50 hingga 200 ms tambahan per transaksi). Untuk pipeline di mana latensi bersifat kritis dan logika pemrosesan sudah idempoten, semantik at-least-once dengan commit manual mungkin merupakan pilihan yang lebih tepat.
Transaksi Kafka menjamin exactly-once di dalam ekosistem Kafka (consume-transform-produce). Untuk exactly-once secara end-to-end ke sistem eksternal (database, warehouse), diperlukan kombinasi transaksi Kafka dengan penulisan idempoten di sistem tujuan.
Share Groups: Model Konsumsi Baru di Kafka 4.x
Kafka 4.0 memperkenalkan Share Groups, sebuah model konsumsi yang memungkinkan beberapa consumer memproses pesan dari partisi yang sama secara bersamaan. Berbeda dengan consumer group klasik di mana setiap partisi ditetapkan secara eksklusif ke satu consumer, Share Groups mendistribusikan pesan individual di antara anggota group.
Model ini sangat berguna untuk beban kerja di mana urutan tidak kritis tetapi paralelisme sangat dibutuhkan (pemrosesan notifikasi, validasi independen, tugas pengayaan tanpa state). Share Groups memungkinkan penskalaan consumer melampaui jumlah partisi, menghilangkan batasan historis Kafka.
| Fitur | Consumer Groups | Share Groups | |---|---|---| | Partition assignment | Exclusive (one consumer per partition) | Shared (multiple consumers per partition) | | Ordering guarantee | Per-partition ordering preserved | No ordering guarantee | | Use case | Ordered event streams | Task distribution, work queues | | Acknowledgement | Offset-based (commit position) | Per-record (acknowledge individually) | | Max parallelism | Limited by partition count | Limited by consumer count |
Share Groups tidak menggantikan consumer group tradisional. Keduanya merupakan alat yang saling melengkapi untuk skenario di mana Kafka digunakan sebagai antrean kerja (work queue) dibandingkan sebagai ordered log. Pemilihan antara kedua model bergantung pada apakah urutan pesan merupakan persyaratan pipeline yang bersangkutan.
Pertanyaan Wawancara Data Engineering tentang Kafka
Wawancara teknis untuk posisi data engineering kerap menyertakan pertanyaan seputar Kafka. Berikut adalah topik-topik yang paling umum beserta jawaban yang diharapkan.
Bagaimana Kafka menjamin urutan pesan? Kafka menjamin urutan hanya di dalam satu partisi. Untuk mempertahankan urutan event yang saling berkaitan, diperlukan partition key yang mengelompokkan event-event tersebut ke partisi yang sama (misalnya, customer_id untuk event dari satu pelanggan).
Apa perbedaan antara at-least-once dan exactly-once? Dengan at-least-once, sebuah pesan dapat diproses lebih dari satu kali apabila consumer gagal setelah memproses tetapi sebelum melakukan commit offset. Exactly-once menggunakan transaksi untuk mengonfirmasi offset consumer dan produksi pesan yang telah ditransformasi secara atomik.
Bagaimana mekanisme rebalancing pada consumer group? Ketika sebuah consumer bergabung atau meninggalkan group, Kafka mendistribusikan ulang partisi di antara anggota yang aktif. Selama rebalancing, pemrosesan terhenti. Protokol Cooperative Sticky Assignor meminimalkan gangguan dengan hanya menetapkan ulang partisi yang diperlukan.
Apa yang terjadi ketika consumer memerlukan waktu terlalu lama untuk memproses?
Apabila waktu antara pemanggilan poll() melebihi max.poll.interval.ms, Kafka menganggap consumer tersebut sudah tidak aktif dan memicu rebalancing. Solusinya adalah mengurangi ukuran batch, meningkatkan interval, atau memproses di thread terpisah.
Mengapa Kafka 4.x menghapus ZooKeeper? ZooKeeper menambahkan kompleksitas operasional, membatasi skalabilitas metadata, dan memerlukan kluster terpisah dengan pengelolaannya sendiri. KRaft mengintegrasikan pengelolaan metadata langsung ke dalam broker Kafka, menyederhanakan deployment dan mempercepat pemulihan dari kegagalan.
Kapan sebaiknya menggunakan Share Groups dibandingkan consumer group? Share Groups cocok digunakan ketika urutan pesan tidak diperlukan dan penskalaan consumer melampaui jumlah partisi dibutuhkan. Model ini ideal untuk beban kerja bertipe antrean kerja (job queue) seperti pemrosesan notifikasi atau validasi independen.
Bagaimana cara mencegah hot partition? Dengan memantau lag per partisi dan distribusi key. Apabila sebuah key memusatkan terlalu banyak pesan, dapat digunakan key komposit, menambahkan sufiks acak (dengan konsekuensi kehilangan urutan), atau melakukan repartisi topic dengan jumlah partisi yang lebih banyak.
Kesimpulan
Apache Kafka merupakan komponen sentral dalam arsitektur data engineering modern untuk pemrosesan data secara real-time. Berikut adalah poin-poin kunci yang perlu dikuasai oleh setiap data engineer:
- Kafka 4.x menghapus ZooKeeper dan menggantinya dengan KRaft, menyederhanakan deployment serta memungkinkan penskalaan pengelolaan metadata hingga jutaan partisi
- Pemilihan partition key menentukan urutan, paralelisme, dan distribusi beban. Gunakan customer_id untuk pipeline pesanan dan session_id untuk data clickstream
- Consumer group dengan commit offset manual memberikan semantik at-least-once, pola yang paling umum dalam pipeline ingestion ke data warehouse
- CDC dengan Debezium menangkap perubahan pada level baris dari PostgreSQL, MySQL, atau MongoDB tanpa membebani database operasional dengan query ekstraksi
- Transaksi Kafka mengaktifkan exactly-once di dalam ekosistem Kafka, membungkus siklus consume-transform-produce dalam satu operasi atomik
- Share Groups di Kafka 4.x memungkinkan penskalaan consumer melampaui jumlah partisi untuk beban kerja di mana urutan pesan tidak kritis
- Dalam wawancara teknis, penguasaan terhadap partisi, semantik pengiriman, rebalancing consumer group, serta perbedaan antara KRaft dan ZooKeeper merupakan hal yang diharapkan
Mulai berlatih!
Uji pengetahuan Anda dengan simulator wawancara dan tes teknis kami.
Tag
Bagikan
Artikel terkait

ETL vs ELT di 2026: Panduan Lengkap Arsitektur Data Pipeline
Pelajari perbedaan mendasar antara ETL dan ELT dalam data engineering modern. Panduan komprehensif arsitektur data pipeline dengan contoh kode Python dan dbt untuk membangun sistem yang scalable.

Apache Spark dengan Python: Membangun Pipeline Data Langkah demi Langkah
Tutorial PySpark untuk membangun pipeline data ETL dengan Spark 4.0. Panduan lengkap DataFrame, Python Data Source API, dan optimasi performa.

25 Pertanyaan Wawancara Data Engineering Terpopuler di Tahun 2026
Panduan komprehensif berisi 25 pertanyaan wawancara data engineering yang paling sering diajukan di tahun 2026, dilengkapi jawaban mendalam, contoh kode, dan strategi persiapan untuk kandidat di semua level.