Event-driven Architecture dengan Messaging Pub/Sub

Muhammad Aditya Hilmy
HMIF ITB Tech
Published in
7 min readDec 2, 2018

Pernahkah kamu terpikir bagaimana perusahaan teknologi seperti Google atau GO-JEK dapat menerima dan memproses sekian banyak data tiap menitnya? Atau pernahkah kamu terpikir bagaimana caranya menerima dan memproses data yang hampir real time?

Cara sederhana menerima dan mengolah data

Secara sederhana, data yang bersumber dari luar — misalnya perangkat IoT — dikirimkan ke server melalui HTTP REST API, kemudian data tersebut langsung diolah oleh server aplikasi dan disimpan ke dalam sebuah basis data.

Ilustrasi pemrosesan data sederhana

Cara seperti ini adalah cara yang paling intuitif, karena menyerupai sebuah prosedur (ada input, pemrosesan, dan output). Namun, cara seperti ini menjadi masalah apabila prosedur pemrosesan sangat kompleks. Ukuran aplikasi bisa menjadi besar dan jika ada sedikit perubahan pada prosedur tersebut, keseluruhan aplikasi harus di-deploy ulang.

Dekomposisi menjadi Microservices

Apabila prosedur pemrosesan menjadi kompleks, aplikasi pemrosesan tersebut dapat dipecah-pecah menjadi satuan kecil yang disebut dengan microservice. Masing-masing microservice dapat memiliki basis datanya sendiri.

Misalnya ada sebuah aplikasi untuk berbagi video. Saat video diunggah oleh pengguna, video tersebut harus dikompresi menjadi berbagai resolusi dan diberi subtitel menggunakan speech-to-text. Kemudian, teman-teman pengguna tersebut harus diberitahukan melalui push notification. Aplikasi tersebut dapat digambarkan sebagai berikut:

Contoh layanan berbagi video yang disederhanakan

Pada contoh diatas, end user mengirimkan file videonya ke server frontend, kemudian server frontend tersebut akan melakukan REST API request ke empat microservice lainnya. Dapat dilihat bahwa masing-masing microservice memiliki basis datanya sendiri, sehingga apabila ada suatu perubahan pada prosedur pemrosesan data di satu microservice, yang lain tidak akan terganggu.

Namun, menggunakan REST API untuk komunikasi antar microservice memiliki beberapa masalah. REST API merupakan proses yang synchronous, artinya proses tidak akan berlanjut sampai proses sebelumnya selesai. Apabila misalnya koneksi dari frontend ke Video registry service terganggu, maka seluruh prosesnya akan ikut terganggu. Masalah lain adalah adanya coupling yang kuat, artinya suatu microservice harus tahu keberadaan microservice lainnya. Pada contoh diatas, Video upload frontend perlu mengetahui adanya keempat microservice lainnya. Apabila pada suatu hari perlu dilakukan penambahan prosedur, misalnya untuk mendeteksi adanya pelanggaran hak cipta pada video yang diunggah (Copyright detection service), Video registry service perlu diubah agar juga melakukan REST API request ke Copyright detection service.

Pola publish-subscribe

Pada pola publish-subscribe, pertukaran data tidak dilakukan secara langsung — seperti halnya REST API — melainkan difasilitasi oleh sebuah perantara yang dikenal dengan sebutan message broker. Data yang dipertukarkan disebut Message, yang dibagi-bagi ke dalam beberapa topic/class. Masing-masing microservice dapat ‘mendengarkan’ suatu topic (subscribe) atau mengirimkan data kepada topic tertentu (publish).

Konsep di atas dapat dianalogikan sebagai berikut: Agus merupakan seorang reseller sepatu di online shop. Budi merupakan calon pembeli di toko Agus, namun model sepatu yang diinginkan Budi habis, sehingga Budi meminta Agus untuk memberitahukannya apabila sepatu yang diinginkannya sudah tersedia. Cahyo dan Dadang juga menginginkan model sepatu yang sama, dan juga meminta Agus untuk memberitahukannya apabila sudah tersedia.

Pada saat Agus sudah mendapatkan model sepatu yang diinginkan Budi, Caca, dan Dadang, Agus memberitahu mereka bertiga.

Pada analogi diatas, Agus bertindak sebagai message broker, Budi, Caca, dan Dadang bertindak sebagai subscriber, dan supplier sepatu bertindak sebagai publisher, serta messagenya adalah informasi bahwa sepatu yang dipesan sudah tersedia. Supplier tidak perlu mengetahui siapa yang akan mendapatkan informasi tersebut selain Agus (message broker) dan Budi, Caca, serta Dadang tidak perlu mengetahui dari mana informasi tersebut awalnya berasal.

Message queueing

Prinsip message queueing sebetulnya sederhana, yaitu message yang akan diproses oleh suatu sistem akan diantrikan terlebih dahulu sebelum diproses satu persatu. Pada synchronous call seperti REST API, interaksi antara publisher dan consumer berlangsung pada saat yang sama. Lain halnya pada message queueing, karena data yang akan diproses diantrikan terlebih dahulu dan akan dikirim ke consumer saat consumer tersebut siap menerima data, pengiriman dan penerimaan data bisa terjadi pada waktu yang berbeda (asynchronous).

Ilustrasi message queueing. Copyright © 2018 Walt Disney Animation Studios

Message queueing dapat digunakan apabila adanya perbedaan antara laju kedatangan data dan laju pemrosesan data. Pada pola client-server konvensional, apabila suatu server dapat memroses 50 data per detik dan kenyataannya menerima 100 data per detik, maka hasilnya sulit untuk diprediksi. Sebagian data akan berhasil diproses, namun sebagian lagi akan gagal diproses karena timeout. Ibarat mulut seseorang yang hanya mampu memakan 20 permen coklat sekaligus yang dipaksa untuk memakan 50 permen coklat sekaligus. Sebagian akan tertelan, sebagian lagi akan dikeluarkan dari mulut (yuck..). Sedangkan, pada pola message queueing, apabila terjadi kasus yang sama seperti di atas, 50 data akan diproses terlebih dahulu, kemudian 50 sisanya akan tertunda sedikit, namun tetap akan diproses. Pada gambar di atas, kelinci tersebut melahap pancake satu persatu dan tidak sekaligus.

Message broker: menggabungkan pub/sub dan message queueing

Message broker yang siap pakai seperti Apache Kafka atau RabbitMQ biasanya menggabungkan pola publish-subscribe dengan message queueing. Pada artikel ini, yang akan dibahas adalah RabbitMQ.

RabbitMQ memiliki dua struktur utama, yaitu Exchange dan Queue. Queue — seperti namanya — adalah antrian data yang akan masuk ke consumer. Satu Queue dapat memiliki lebih dari satu consumer dan data akan didistribusikan secara bergantian (baca: round robin dispatching). Exchange merupakan tempat message didistribusikan ke banyak Queue.

Ilustrasi struktur RabbitMQ. Sumber: rabbitmq.com

Secara singkat, message yang dikirimkan oleh publisher P ke Exchange X tidak langsung dikirimkan ke subscriber C1 dan C2, tetapi dimasukkan terlebih dahulu ke antrian milik C1 dan C2, yang kemudian diproses oleh C1 dan C2 satu persatu. Exchange sebetulnya adalah sebuah topic (sudah dibahas di atas). Pada contoh diatas, C1 dan C2 men-subscribe pada topic X.

Model seperti ini sangatlah scalable. Misalkan laju kedatangan data adalah 100 data per detik dan laju pemrosesan data masing-masing consumer adalah 25 data per detik, kita dapat menjalankan 4 buah consumer yang memroses dari Queue yang sama. Apabila suatu saat tiba-tiba laju kedatangan data melonjak menjadi 200 data per detik, kita dapat menambahkan 4 buah consumer lagi. Apabila consumer tidak ditambah, data tetap akan diproses, namun membutuhkan waktu yang lebih lama.

Event-driven architecture (EDA)

Menurut definisi dari Wikipedia,

Event-driven architecture (EDA), is a software architecture pattern promoting the production, detection, consumption of, and reaction to events.

Pada model EDA, data yang diterima dari luar tidak langsung disimpan ke basis data, juga tidak langsung diproses pada saat data diterima. EDA memanfaatkan kedua pola yang telah dibahas sebelumnya. Apabila contoh layanan berbagi video yang dibahas pada bagian “Dekomposisi menjadi Microservices” dibuat menggunakan model EDA, kurang lebih akan menjadi seperti berikut:

Contoh event-driven architecture

Arsitektur yang menggunakan EDA memang terlihat lebih rumit ketimbang yang konvensional, namun EDA memiliki kelebihan, diantaranya:

  1. Pada contoh diatas, video dapat diproses secara asynchronous, sehingga pengguna tidak perlu menunggu pemrosesan videonya selesai (i.e. HTTP request bisa dengan cepat diakhiri).
  2. Compression service dan Subtitle service dapat berjalan secara paralel.
  3. Sangat scalable. Jumlah consumer dapat ditambah apabila tidak cukup.
  4. Apabila jumlah consumer tidak cukup, video tetap dapat bisa diproses, namun membutuhkan waktu yang lama.
  5. Loosely coupled. Artinya, antara sebuah microservice tidak perlu mengetahui keberadaan microservice yang lainnya. Apabila perlu ditambahkan suatu microservice baru, misalnya microservice untuk mendeteksi pelanggaran hak cipta pada video — seperti pada contoh sebelumnya, microservice baru tersebut hanya perlu men-subscribe ke topic yang diperlukan tanpa mengubah aplikasi lainnya.

Sebagai penutup, event-driven architecture merupakan arsitektur sistem yang fleksibel, scalable, dan reliable dalam mengolah data yang bervolume besar dan membutuhkan pemrosesan kompleks. Apabila kamu penasaran tentang arsitektur data di GO-JEK, silakan baca artikel yang dipublikasikan oleh GO-JEK Engineering:

--

--