# Arsitektur Event-Driven dengan Kafka dan NestJS: Panduan Produksi

> Cara membangun sistem event-driven yang kuat menggunakan Apache Kafka dan NestJS — dari desain topik hingga consumer group, penanganan error, dan tuning produksi.

URL: https://www.matthewswong.com/id/blog/event-driven-kafka-nestjs/

- Author: Matthews Wong (https://www.matthewswong.com/id/about/)
- Published: 2025-06-10
- Updated: 2026-10-17
- Category: DevOps

Apache Kafka dapat mempertahankan 2 juta tulis per detik pada tiga mesin komoditas — tolok ukur yang dipublikasikan LinkedIn yang masih berlaku hingga hari ini. Angka itu sering membuat developer langsung memilih Kafka. Namun saya telah belajar bahwa throughput bukan pertanyaan pertama yang harus diajukan. Pertanyaan pertama adalah: apakah masalah Anda benar-benar membutuhkan event bus? Banyak beban kerja ERP, seperti pemicu email dan pembuatan invoice, sudah terlayani dengan baik oleh antrian berbasis database sederhana — dan itu adalah keputusan yang tepat untuk beban kerja tersebut. Kafka memperoleh kompleksitasnya ketika beberapa layanan perlu bereaksi terhadap event yang sama secara independen, ketika Anda membutuhkan replay event yang tahan lama, atau ketika Anda memproses jutaan event setiap hari.

## Memahami Model Inti Kafka

Arsitektur Kafka dibangun di sekitar topik, partisi, dan consumer group. Topik adalah kategori event — seperti 'order.created' atau 'invoice.paid'. Topik dibagi menjadi partisi, yang merupakan unit paralelisme. Setiap partisi adalah urutan rekaman yang berurutan dan tidak dapat diubah yang disimpan Kafka untuk periode yang dapat dikonfigurasi (default 7 hari). Consumer group memungkinkan beberapa instansi layanan membaca dari topik secara paralel.

### Merancang Topik dan Partisi

Desain topik adalah tempat di mana kebanyakan tim membuat kesalahan. Terlalu sedikit partisi membatasi paralelisme — jika Anda memiliki satu partisi, hanya satu consumer yang dapat membacanya sekaligus. Titik awal yang wajar: atur jumlah partisi sama dengan konkurensi consumer puncak yang Anda harapkan. Gunakan kunci partisi yang bermakna — biasanya ID tenant, ID pengguna, atau ID entitas — sehingga event terkait mendarat di partisi yang sama dan mempertahankan urutan untuk entitas tersebut.

> Dari pengalaman membangun modul event-driven untuk sistem ERP: gunakan nama topik yang deskriptif dan berversi seperti 'erp.v1.invoice.created' dari awal. Mengganti nama topik di produksi memerlukan koordinasi semua produsen dan consumer secara bersamaan — migrasi yang menyakitkan. Sertakan domain, versi, entitas, dan kata kerja event dalam nama, dan Anda akan berterima kasih pada diri sendiri ketika menambahkan skema v2 enam bulan kemudian.

## Mengimplementasikan Kafka di NestJS dengan @nestjs/microservices

NestJS memiliki dukungan Kafka kelas pertama melalui paket @nestjs/microservices. Anda mengonfigurasi transport microservice Kafka di aplikasi Anda, kemudian menggunakan dekorator untuk mendefinisikan message handler. Pengaturannya memerlukan tiga bagian: layanan produsen (untuk menerbitkan event), modul consumer (dengan dekorator @EventPattern atau @MessagePattern), dan konfigurasi klien Kafka dengan pengaturan retry dan penanganan error yang tepat.

### Penanganan Error dan Dead Letter Queue

Kafka produksi tanpa dead letter queue (DLQ) adalah jebakan. Ketika consumer melempar error yang tidak tertangani, perilaku default mencoba ulang tanpa batas — memblokir partisi tersebut dari maju. Tetapkan kebijakan retry yang dibatasi dan arahkan pesan yang gagal ke topik DLQ (misalnya 'erp.v1.invoice.created.dlq'). Consumer DLQ terpisah dapat memberi peringatan tentang kegagalan, menyimpannya untuk inspeksi manual, dan memutarnya ulang setelah perbaikan bug.

> **Jangan gunakan Kafka untuk beban kerja kecil**

> Kafka memerlukan kluster ZooKeeper atau KRaft, tuning partisi yang tepat, strategi rebalancing consumer group, monitoring, dan schema registry jika Anda ingin evolusi skema. Untuk ERP yang menangani 500 event per hari, antrian berbasis PostgreSQL dengan pg-boss atau antrian Redis BullMQ sederhana memberikan 90% manfaat dengan 10% kompleksitas operasional. Saya menggunakan Kafka hanya ketika beberapa layanan independen harus mengonsumsi aliran event yang sama.

## Consumer Group dan Skalabilitas

Consumer group adalah mekanisme skalabilitas horizontal Kafka. Tambahkan instansi baru layanan consumer NestJS Anda, dan Kafka secara otomatis menyeimbangkan ulang partisi di semua instansi. Tangkapannya: selama rebalance, semua consumer dalam grup berhenti memproses sementara partisi ditugaskan ulang. Untuk sistem latensi rendah, jaga waktu rebalance consumer group tetap pendek dengan menggunakan fitur keanggotaan statis.

## Manajemen Skema dengan Schema Registry

Seiring pertumbuhan sistem event-driven Anda, evolusi skema menjadi masalah paling sulit. Saat event 'order.created' mendapatkan kolom wajib baru, ada jendela waktu di mana produsen lama mengirim event tanpa kolom tersebut dan consumer baru mengharapkannya. Confluent Schema Registry (atau ekuivalen open-source-nya seperti Apicurio) memecahkan ini dengan versi skema dan pemeriksaan kompatibilitas.

## Penilaian Jujur Saya: Kapan Memilih Kafka

Gunakan Kafka ketika: (1) beberapa layanan independen perlu mengonsumsi aliran event yang sama; (2) Anda membutuhkan replay event yang tahan lama untuk debugging atau membangun read model; (3) Anda memproses jutaan event setiap hari dan membutuhkan skala horizontal; (4) Anda memiliki tim dengan kapasitas untuk mengoperasikan kluster Kafka. Lewati Kafka ketika: sistem Anda memiliki kurang dari 3 layanan yang mengonsumsi event, throughput Anda di bawah 10K event/hari, atau tim Anda tidak memiliki pengalaman operasional Kafka.

## Sumber & Bacaan Lebih Lanjut

- LinkedIn Engineering — Benchmarking Apache Kafka: 2 Million Writes Per Second
- Confluent — Kafka Performance: Throughput, Latency, and Test Results
- NestJS Docs — Microservices: Kafka Transport

## Source links

- https://engineering.linkedin.com/kafka/benchmarking-apache-kafka-2-million-writes-second-three-cheap-machines
- https://developer.confluent.io/learn/kafka-performance/
- https://docs.nestjs.com/microservices/kafka

## FAQ

### Kapan sebaiknya saya memilih Kafka daripada antrian yang lebih sederhana seperti BullMQ atau pg-boss?

Kafka memperoleh kompleksitasnya ketika beberapa layanan independen perlu mengonsumsi aliran event yang sama, ketika Anda membutuhkan replay event yang tahan lama, atau ketika Anda memproses jutaan event setiap hari. Untuk sistem dengan kurang dari 3 layanan yang mengonsumsi event atau throughput di bawah 10K event per hari, BullMQ dengan Redis menangani antrean, retry, dan prioritas dengan kompleksitas operasional yang jauh lebih rendah. Antrian berbasis database sederhana sering kali sudah cukup untuk beban kerja ERP seperti pemicu email dan pembuatan invoice.

### Bagaimana cara merancang nama topik Kafka yang baik untuk lingkungan produksi?

Gunakan nama topik yang deskriptif dan berversi yang mencakup domain, versi, entitas, dan kata kerja event — misalnya 'erp.v1.invoice.created'. Menetapkan konvensi ini dari awal sangat penting karena mengganti nama topik di produksi memerlukan koordinasi semua produsen dan consumer secara bersamaan, yang merupakan migrasi yang menyakitkan. Skema penamaan ini juga memudahkan penambahan skema v2 di kemudian hari tanpa merusak consumer yang sudah ada.

### Apa itu Dead Letter Queue (DLQ) dan mengapa penting dalam setup Kafka produksi?

DLQ adalah topik terpisah tempat pesan diarahkan ketika consumer gagal memprosesnya setelah jumlah retry yang dibatasi. Tanpa DLQ, error consumer yang tidak tertangani menyebabkan Kafka mencoba ulang tanpa batas, memblokir partisi tersebut dari maju. Di NestJS, error handler harus menangkap kegagalan, mencatat pesan ke topik DLQ (misalnya 'erp.v1.invoice.created.dlq'), dan mengakui pesan asli — memungkinkan peringatan, inspeksi manual, dan pemutaran ulang setelah perbaikan bug.

### Bagaimana consumer group memungkinkan skalabilitas horizontal pada layanan Kafka di NestJS?

Setiap partisi dalam topik Kafka ditugaskan ke tepat satu consumer dalam grup pada satu waktu, sehingga menambahkan instansi consumer NestJS baru menyebabkan Kafka secara otomatis menyeimbangkan ulang partisi di semua instansi. Hal penting yang perlu diperhatikan adalah bahwa selama rebalance, semua consumer dalam grup berhenti memproses sementara partisi ditugaskan ulang. Untuk meminimalkan dampak rebalance, gunakan fitur keanggotaan statis Kafka agar rolling restart tidak memicu rebalance yang tidak perlu, dan jaga jumlah partisi mendekati jumlah consumer yang diharapkan.

### Bagaimana Schema Registry mengatasi evolusi skema dalam sistem event-driven?

Ketika kolom wajib baru ditambahkan ke skema event yang sudah ada, ada jendela waktu di mana produsen lama mengirim event tanpa kolom tersebut sementara consumer baru mengharapkannya. Confluent Schema Registry (dan alternatif open-source seperti Apicurio) mengatasi ini dengan menegakkan versi skema dan pemeriksaan kompatibilitas. Menegakkan kompatibilitas 'BACKWARD' berarti skema baru dapat membaca pesan yang ditulis oleh skema lama, memungkinkan consumer diperbarui sebelum produsen tanpa memerlukan deployment yang terkoordinasi.

---

- HTML version: https://www.matthewswong.com/id/blog/event-driven-kafka-nestjs/
- English: https://www.matthewswong.com/en/blog/event-driven-kafka-nestjs/
- Site index for agents: https://www.matthewswong.com/llms.txt
- Sitemap: https://www.matthewswong.com/sitemap.xml
- API description (OpenAPI): https://www.matthewswong.com/openapi.json
