Overview
Selama lebih dari dua dekade, arsitektur batch processing menjadi tulang punggung pemrosesan data enterprise. Laporan keuangan dihasilkan setiap malam, data warehouse di-refresh setiap beberapa jam, dan reconciliation antar sistem dilakukan secara periodik. Model ini bekerja dengan baik di era ketika latensi pengambilan keputusan masih bisa ditoleransi dalam hitungan jam atau bahkan hari.
Namun, lanskap digital Indonesia telah berubah drastis. Dengan lebih dari 200 juta pengguna internet aktif dan adopsi digital banking, e-commerce, serta super apps yang terus meningkat, kebutuhan akan pemrosesan data real-time bukan lagi kemewahan — melainkan keharusan kompetitif. Sebuah sistem deteksi fraud yang memproses transaksi dalam batch setiap 15 menit berarti ada jendela 15 menit di mana transaksi mencurigakan lolos tanpa terdeteksi. Dalam industri ride-hailing, harga surge yang dihitung berdasarkan data 30 menit yang lalu menghasilkan pricing yang tidak akurat.
Event-Driven Architecture (EDA) menjawab kebutuhan ini dengan mengubah cara fundamental sistem berkomunikasi. Alih-alih memproses data dalam batch besar secara periodik, EDA memungkinkan setiap perubahan state — setiap transaksi, setiap klik, setiap pembacaan sensor — diproses segera saat terjadi. Pergeseran dari "apa yang terjadi dalam 24 jam terakhir?" menjadi "apa yang sedang terjadi sekarang?" membuka peluang bisnis yang sebelumnya tidak mungkin dicapai.
Artikel ini membahas secara mendalam bagaimana event-driven architecture bekerja, mengapa pola ini menjadi standar de facto untuk sistem modern, dan bagaimana organisasi di Indonesia dapat melakukan migrasi secara bertahap dari arsitektur batch ke streaming.
Untuk memahami EDA, kita perlu memahami dulu paradigma yang digantikannya. Dalam arsitektur request-response tradisional, komponen A memanggil komponen B secara langsung, menunggu respons, lalu melanjutkan prosesnya. Ini adalah model sinkronus di mana setiap service harus mengetahui keberadaan service lain dan bergantung pada ketersediaan mereka secara real-time.
Model ini menciptakan tight coupling — perubahan pada satu service berpotensi memengaruhi semua service yang bergantung padanya. Ketika Service B down, Service A tidak bisa menyelesaikan operasinya. Scaling menjadi tantangan karena setiap service dalam chain harus mampu menangani beban yang sama.
Event-driven architecture membalik model ini. Alih-alih Service A memanggil Service B, Service A mempublikasikan event — pernyataan bahwa sesuatu telah terjadi. Service B (dan service lain yang tertarik) mendengarkan event tersebut dan bereaksi secara independen. Inilah yang disebut loose coupling melalui temporal decoupling — producer dan consumer tidak perlu aktif pada waktu yang sama.
Perbedaan kunci lainnya adalah arah ketergantungan. Dalam request-response, pengirim harus mengetahui penerima. Dalam EDA, producer tidak tahu dan tidak peduli siapa yang mengonsumsi event-nya. Ini memungkinkan penambahan consumer baru tanpa mengubah kode producer — sebuah karakteristik yang sangat powerful untuk evolusi sistem jangka panjang.
Namun, penting untuk dicatat bahwa request-response tetap memiliki tempatnya. Operasi yang memerlukan respons langsung — seperti query saldo rekening atau validasi stok sebelum checkout — masih lebih tepat menggunakan model sinkronus. Keputusan antara kedua pola ini bukan tentang mana yang lebih baik secara absolut, melainkan mana yang lebih sesuai untuk use case spesifik.
Di jantung EDA terdapat konsep event — sebuah record immutable yang menyatakan bahwa sesuatu telah terjadi pada titik waktu tertentu. Event berbeda dari command (perintah untuk melakukan sesuatu) dan query (permintaan informasi). Event bersifat past-tense: OrderPlaced, PaymentReceived, InventoryUpdated.
Komponen utama EDA meliputi:
Event Producers adalah komponen yang menghasilkan event. Sebuah payment service menghasilkan event PaymentProcessed, sebuah IoT sensor menghasilkan event TemperatureReading. Producer bertanggung jawab untuk memastikan event dipublikasikan dengan reliabel.
Event Consumers adalah komponen yang bereaksi terhadap event. Sebuah notification service mendengarkan event OrderShipped untuk mengirim email ke customer. Satu event bisa dikonsumsi oleh banyak consumer secara independen.
Event Channels (atau topics/streams) adalah media transport untuk event. Channel memisahkan producer dari consumer dan menyediakan mekanisme buffering, ordering, dan durability.
Event Processors melakukan transformasi, enrichment, filtering, atau agregasi terhadap event streams. Mereka bisa sederhana (filter event berdasarkan kriteria) atau kompleks (menggabungkan multiple streams untuk mendeteksi pola).
Secara konseptual, event dapat dikategorikan menjadi tiga jenis:
LoanApproved, AccountSuspended.Pemilihan jenis event yang tepat memiliki implikasi signifikan terhadap coupling, bandwidth, dan kompleksitas sistem.
Dalam arsitektur tradisional, database menyimpan current state — saldo rekening saat ini adalah Rp 10.000.000. Ketika saldo berubah, nilai lama ditimpa dengan nilai baru. Histori perubahan hilang kecuali secara eksplisit di-log.
Event sourcing membalik pendekatan ini. Alih-alih menyimpan state terkini, sistem menyimpan urutan event yang menghasilkan state tersebut:
AccountCreated { balance: 0 }
MoneyDeposited { amount: 15_000_000 }
MoneyWithdrawn { amount: 3_000_000 }
MoneyDeposited { amount: 500_000 }
TransferSent { amount: 2_500_000 }
Current state (Rp 10.000.000) dapat dihitung kapan saja dengan memutar ulang (replaying) seluruh event dari awal. Ini memberikan beberapa keuntungan signifikan:
Full audit trail — setiap perubahan tercatat dengan timestamp, actor, dan konteks lengkap. Untuk industri yang teregulasi seperti perbankan dan kesehatan, ini bukan fitur tetapi keharusan compliance.
Temporal queries — kemampuan untuk mengetahui state sistem pada titik waktu tertentu di masa lalu. "Berapa saldo rekening ini pada tanggal 15 Januari pukul 14:30?" bisa dijawab dengan memutar ulang event hingga titik waktu tersebut.
Debugging yang lebih baik — ketika terjadi bug, developer dapat memutar ulang event untuk mereproduksi kondisi yang menyebabkan masalah, alih-alih menebak-nebak dari snapshot state terkini.
Namun, event sourcing bukan tanpa tradeoff. Kompleksitas implementasi meningkat signifikan — developer harus berpikir dalam terms of events alih-alih CRUD operations. Storage requirement juga lebih besar karena event tidak pernah dihapus (hanya di-snapshot secara periodik untuk optimasi performa). Query terhadap current state memerlukan mekanisme tambahan seperti projections atau read models, yang membawa kita ke konsep CQRS.
Command Query Responsibility Segregation (CQRS) adalah pola arsitektur yang memisahkan model untuk operasi write (commands) dari model untuk operasi read (queries). Dalam sistem CRUD tradisional, model yang sama digunakan untuk menyimpan dan membaca data — sering kali menyebabkan kompromi di kedua sisi.
Dalam CQRS, command model dioptimasi untuk memvalidasi dan memproses perubahan state. Ia bisa menggunakan event sourcing, domain model yang kaya, atau storage apapun yang optimal untuk operasi write. Sementara query model dioptimasi untuk membaca data — bisa berupa denormalized views, search indexes, atau materialized views yang dirancang khusus untuk pola akses baca yang spesifik.
Kedua model disinkronkan melalui event: ketika command model memproses perubahan, event dipublikasikan, dan query model di-update secara asinkronus. Ini berarti query model bersifat eventually consistent — ada jeda waktu (biasanya milidetik hingga beberapa detik) antara perubahan terjadi dan query model ter-update.
CQRS sangat cocok untuk skenario di mana:
Namun, CQRS menambah kompleksitas operasional. Eventual consistency memerlukan penanganan khusus di UI ("data Anda sedang diproses"), dan infrastruktur untuk menjaga sinkronisasi antara command dan query model harus robust. Untuk domain yang sederhana dengan pola akses yang straightforward, CQRS biasanya merupakan over-engineering.
Apache Kafka telah menjadi platform de facto untuk event streaming di level enterprise. Didesain oleh tim LinkedIn dan kemudian diopen-source-kan, Kafka dibangun untuk menangani throughput yang sangat tinggi dengan latensi rendah dan durabilitas tinggi.
Arsitektur Kafka terdiri dari beberapa komponen kunci:
Durability dijamin melalui replication. Setiap partition bisa dikonfigurasi dengan replication factor — misalnya, replication factor 3 berarti setiap record disimpan di 3 broker berbeda. Jika satu broker gagal, data tetap tersedia dari replika lain.
Tuning Kafka memerlukan pemahaman tentang tradeoff antara throughput dan latensi. Batch size yang lebih besar meningkatkan throughput tetapi menambah latensi. Compression mengurangi network bandwidth tetapi menambah CPU overhead. acks=all memberikan durability tertinggi tetapi mengurangi throughput karena producer harus menunggu semua replika mengonfirmasi write.
Kafka Streams adalah library untuk membangun aplikasi stream processing langsung di atas Kafka. Berbeda dengan framework seperti Apache Flink atau Spark Streaming yang memerlukan cluster terpisah, Kafka Streams berjalan sebagai library dalam aplikasi Java/Kotlin biasa — membuatnya lebih mudah di-deploy dan dikelola.
ksqlDB membawa stream processing ke level aksesibilitas yang lebih tinggi dengan menyediakan SQL interface untuk Kafka Streams. Query seperti SELECT user_id, COUNT(*) FROM clicks WINDOW TUMBLING (SIZE 5 MINUTES) GROUP BY user_id memungkinkan developer yang familiar dengan SQL untuk melakukan stream processing tanpa menulis kode Java.
Penting untuk memahami perbedaan fundamental antara message brokers tradisional (RabbitMQ, ActiveMQ) dan event streaming platforms (Kafka, Apache Pulsar, Redpanda).
Message brokers didesain untuk model publish-subscribe di mana pesan dikonsumsi dan dihapus. Mereka unggul dalam routing yang kompleks (topic exchanges, fanout, header-based routing) dan mendukung protokol standar seperti AMQP. Namun, setelah pesan dikonsumsi, ia hilang dari broker.
Event streaming platforms memperlakukan event stream sebagai log yang persisten. Event disimpan untuk periode yang dikonfigurasi (atau selamanya) dan bisa di-replay kapan saja. Consumer baru bisa mulai membaca dari awal stream, memungkinkan reprocessing historis. Ini adalah perbedaan fundamental yang memungkinkan use case seperti event sourcing, CDC, dan temporal queries.
Keputusan antara keduanya bergantung pada kebutuhan:
| Kriteria | Message Broker | Event Streaming |
|---|---|---|
| Message retention | Hapus setelah dikonsumsi | Persisten (configurable) |
| Replay capability | Tidak | Ya |
| Ordering | Per-queue | Per-partition |
| Routing complexity | Tinggi (exchanges, bindings) | Sederhana (topic-based) |
| Throughput | Moderat | Sangat tinggi |
| Use case utama | Task distribution, RPC | Event sourcing, CDC, analytics |
Dalam praktiknya, banyak organisasi menggunakan keduanya: RabbitMQ untuk task queuing dan command distribution, Kafka untuk event streaming dan data pipeline.
Dalam sistem event-driven yang melibatkan banyak tim dan service, salah satu tantangan terbesar adalah evolusi schema. Ketika producer mengubah format event — menambah field, mengubah tipe data, menghapus field — consumer yang bergantung pada format lama bisa rusak.
Schema Registry (seperti Confluent Schema Registry) mengatasi masalah ini dengan menyimpan dan mengelola schema untuk setiap topic. Setiap event yang dipublikasikan harus sesuai dengan schema yang terdaftar, dan schema baru harus kompatibel dengan versi sebelumnya.
Kompatibilitas schema memiliki beberapa level:
Untuk format serialisasi, tiga opsi utama adalah:
Pendekatan contract-first — mendefinisikan schema sebelum menulis kode — menjadi best practice untuk memastikan semua tim memiliki pemahaman yang sama tentang format data dan mencegah breaking changes.
Event-driven architecture bukan sekadar teori — ia memecahkan masalah bisnis nyata di berbagai industri:
Real-time fraud detection (perbankan): Setiap transaksi kartu kredit menghasilkan event yang langsung dievaluasi oleh model ML secara real-time. Pattern seperti transaksi beruntun di lokasi yang berjauhan dalam waktu singkat bisa terdeteksi dalam milidetik, bukan menit atau jam seperti dalam sistem batch.
Change Data Capture / CDC (sinkronisasi sistem): Tools seperti Debezium membaca transaction log dari database sumber dan mempublikasikan setiap perubahan sebagai event ke Kafka. Ini memungkinkan sinkronisasi near-real-time antara database operasional, data warehouse, search index, dan cache — tanpa mengubah kode aplikasi sumber.
IoT sensor streaming (manufaktur): Ribuan sensor di lantai produksi menghasilkan event pembacaan temperatur, tekanan, dan vibrasi. Stream processing menganalisis data ini secara real-time untuk mendeteksi anomali dan melakukan predictive maintenance sebelum mesin mengalami kegagalan.
Order processing (e-commerce): Event OrderPlaced memicu cascade of actions secara paralel — validasi pembayaran, pengecekan inventory, notifikasi ke warehouse, update tracking, dan pengiriman konfirmasi ke customer. Semua terjadi secara asinkronus dan independen.
Inventory synchronization (retail): Untuk retailer dengan ratusan toko dan marketplace online, setiap perubahan stok di satu channel langsung terpropagasi ke semua channel lain melalui event streaming, mengurangi overselling dan meningkatkan akurasi stok.
Adopsi EDA tanpa pemahaman yang matang sering menghasilkan anti-patterns yang merugikan:
Event explosion — mempublikasikan event untuk setiap perubahan kecil tanpa mempertimbangkan apakah event tersebut benar-benar bernilai bagi consumer. Ini membanjiri sistem dengan noise dan meningkatkan biaya infrastruktur. Solusinya: hanya publikasikan event yang merepresentasikan perubahan bisnis yang signifikan.
Temporal coupling — ketika consumer mengasumsikan event akan tiba dalam urutan tertentu atau dalam time window tertentu. Ini mengembalikan coupling yang seharusnya dihilangkan oleh EDA. Desain consumer yang toleran terhadap out-of-order dan delayed events.
Missing idempotency — dalam distributed systems, event bisa terkirim lebih dari sekali (at-least-once delivery). Jika consumer tidak idempoten, pemrosesan duplikat bisa menyebabkan data corruption. Implementasikan deduplication menggunakan event ID atau idempotency keys.
Unbounded event streams — tidak mengimplementasikan retention policy atau compaction pada event streams, menyebabkan storage yang terus membengkak tanpa batas. Konfigurasi retention yang sesuai berdasarkan kebutuhan bisnis dan compliance.
Event-driven spaghetti — kurangnya governance atas event schemas dan event flows menyebabkan spaghetti architecture versi distributed. Tanpa event catalog, schema registry, dan dokumentasi yang jelas, debugging menjadi mimpi buruk. Investasi dalam tooling observability dan event discovery.
Migrasi dari arsitektur batch ke streaming adalah perjalanan bertahap, bukan revolusi big-bang. Berikut strategi yang proven:
Hindari dual-write. Menulis ke database dan message broker secara bersamaan dalam satu operasi menciptakan race condition dan risiko inkonsistensi. Jika write ke database berhasil tetapi publish ke broker gagal (atau sebaliknya), sistem berada dalam state yang inkonsisten.
Outbox pattern mengatasi masalah dual-write. Alih-alih menulis ke database dan broker secara terpisah, tulis event ke tabel outbox dalam transaksi database yang sama dengan perubahan data. Proses terpisah kemudian membaca dari tabel outbox dan mempublikasikan ke broker. Ini menjamin konsistensi karena write ke outbox dan data terjadi dalam satu transaksi database.
CDC-based migration adalah pendekatan yang paling non-invasif. Debezium atau tool CDC lainnya membaca langsung dari database transaction log dan mempublikasikan perubahan sebagai event. Kode aplikasi existing tidak perlu diubah sama sekali — CDC berjalan sebagai proses terpisah yang "mendengarkan" perubahan di level database.
Gradual adoption strategy yang direkomendasikan:
Koeksistensi batch dan streaming adalah realitas di sebagian besar organisasi. Tidak semua proses perlu real-time — monthly financial reporting, historical analytics, dan regulatory reporting mungkin tetap lebih sesuai dengan batch processing. Kuncinya adalah memilih pola yang tepat untuk setiap use case berdasarkan kebutuhan latensi dan kompleksitas bisnis.
Apakah event-driven architecture cocok untuk semua jenis aplikasi? Tidak. EDA paling cocok untuk sistem yang memerlukan loose coupling, scalability tinggi, dan pemrosesan real-time. Untuk aplikasi CRUD sederhana dengan sedikit integrasi, arsitektur monolitik tradisional mungkin lebih tepat dan cost-effective. Evaluasi kebutuhan spesifik sebelum mengadopsi EDA.
Bagaimana menangani eventual consistency dalam EDA? Eventual consistency memerlukan perubahan mindset di level UI dan business logic. Gunakan teknik seperti optimistic UI updates (tampilkan perubahan segera di UI sambil memproses di background), polling atau WebSocket untuk notifikasi ketika data sudah konsisten, dan compensating transactions untuk menangani kegagalan. Komunikasikan ekspektasi latensi kepada stakeholder bisnis.
Berapa lama biasanya migrasi dari batch processing ke event streaming? Timeline sangat bervariasi tergantung kompleksitas sistem existing, jumlah integrasi, dan kematangan tim. Untuk satu use case pilot, estimasi 2-4 bulan dari proof of concept hingga production. Migrasi keseluruhan bisa memakan waktu 12-24 bulan secara bertahap. Kunci keberhasilannya adalah mulai kecil, buktikan value, lalu scale secara bertahap.
Migrasi ke event-driven architecture adalah investasi strategis yang memerlukan perencanaan matang, pemilihan teknologi yang tepat, dan eksekusi yang disiplin. Kesalahan di tahap awal — pemilihan messaging platform yang salah, schema design yang tidak scalable, atau migrasi big-bang yang terburu-buru — bisa berdampak jangka panjang.
Divistant memiliki pengalaman mendalam dalam merancang dan mengimplementasikan event-driven architecture untuk enterprise di Indonesia. Dari assessment arsitektur existing, pemilihan technology stack, hingga hands-on implementation dan knowledge transfer ke tim internal Anda — kami memastikan transisi ke real-time streaming berjalan smooth dan memberikan ROI yang terukur.
Hubungi tim kami untuk mendiskusikan bagaimana event-driven architecture dapat mentransformasi operasional bisnis Anda.
Related Tags:
Marketing