Implementasi RabbitMQ untuk Komunikasi Microservices pada Node.js

Faldy Ikhwan Fadila
ITMI Engineering
Published in
5 min readSep 3, 2020

Ketika sistem yang monolithic sudah tidak sanggup untuk mengangkat jumlah request per second yang cukup besar pada back-end, maka perlu adanya optimasi. Mulai dari implementasi load balancer, caching, optimasi kode, hingga migrasi ke sistem yang berjenis microservices. Kali ini, saya akan mencoba mengimplementasikan RabbitMQ ini untuk digunakan sebagai metode komunikasi antar service pada arsitektur microservices.

Apa itu RabbitMQ?

RabbitMQ adalah salah satu message broker open-source yang dapat kita gunakan untuk komunikasi pada sistem yang terdistribusi seperti microservices. RabbitMQ ini cukup ringan dan dapat diinstall pada berbagai sistem operasi dengan mudah. RabbitMQ juga berperan sebagai antrian, yang mana akan melayani request dari yang pertama masuk atau yang bisa disebut FIFO (First In First Out).

Mengapa menggunakan RabbitMQ sebagai media komunikasi? Kenapa tidak menggunakan HTTP saja?

Ketika salah satu service mengalami kegagalan, maka HTTP pattern akan berhenti bekerja. Dan juga setelah restart, tidak ada cara untuk melacak HTTP request sebelumnya, sehingga bisa membuat tingkat kegagalan pada suatu sistem menjadi cukup tinggi. Maka dari itu, kita membutuhkan RabbitMQ, yang mana akan membantu kita untuk scale up sistem pada level tinggi dengan menambahkan mekanisme kegagalan.

RPC Pattern

Untuk penggunaan RabbitMQ nya sendiri, kita akan menggunakan RPC pattern nya, yang mana menurut website guide rabbitMQ nya sendiri merupakan implementasi dari Request-Reply pattern.

Gambar 1. Request Reply Pattern (https://www.enterpriseintegrationpatterns.com/patterns/messaging/RequestReply.html)

Ketika mengimplementasi dengan pattern RPC kita perlu membuka terlebih dahulu reply channel, sehingga kita bisa tahu hasil jawaban dari service tujuan ketika pesan kita sudah selesai dikirimkan dan diproses oleh service yang dituju. Kita juga perlu untuk menandai pesan yang dikirimkan dengan yang disebut correlation ID, yang mana akan menjadi tanda yang akan kita gunakan ketika mengambil balasan dari reply channel yang mungkin bakal ada lebih dari satu pesan. Ketika kita melakukan iterasi pada list pesan yang didapat dan ternyata pesan tersebut memiliki correlation ID yang berbeda, kita bisa membuang pesan tersebut dengan aman karena akan masuk ke requeueing state dan melanjutkan iterasi ke pesan selanjutnya.

Implementasi

Langsung saja lanjut ke tahap implementasi, pada tahap ini kita akan membuat project API blog simpel, yang mana akan ada beberapa blog post. Namun, service untuk mengambil data pada blog terpisah dengan service yang hanya dikhususkan untuk menyajikan HTTP request.

Pertama-tama kita perlu menyiapkan 2 project Node.js baru. Yang pertama akan kita gunakan sebagai service yang dapat di hit dengan menggunakan HTTP yang mana akan diinstall Express.js dan amqplib. Kemudian yang kedua hanya bertugas di lingkup blog post yang diinstall amqplib saja. Pada pembahasan kali ini, saya tidak menggunakan koneksi ke database melainkan hanya disimpan di file saja.

Gambar 2. Gambaran arsitektur sistem yang akan dibuat

Pada gambar diatas, kita akan menyediakan 1 queue untuk di consume dan 1 queue yang akan digunakan untuk me-listen balasannya.

Persiapan

Sebelum memulai, pastikan sudah menginstall:

  • Erlang (untuk running RabbitMQ)
  • RabbitMQ
  • Node.js

Jika sudah, pertama-tama kita siapkan project dengan struktur sebagai berikut:

.
├── blog-posts-server
│ └── app.js
└── http-server
└── app.js

Kemudian, masuk ke masing-masing project folder dan lakukan npm init. Install juga dependency yang diperlukan oleh project tersebut.

cd blog-posts-server
npm init
npm i
npm i amqplib
cd http-server
npm init
npm i
npm i amqplib express

Implementasi Blog Posts Server

Berikut ini adalah implementasi script pada blog-posts-server yang bertugas untuk memberikan postingan blog berdasarkan ID. Fungsi pada service ini tidak dapat diakses langsung oleh user, melainkan hanya dapat dipanggil melalui antrian RabbitMQ.

Penjelasan code:

  • Sebelum melakukan listen terhadap queue spesifik, kita perlu menginisiasi RabbitMQ connection dan channel terlebih dahulu melalui baris 20–21.
  • Kemudian kita lakukan assertion terhadap queue dengan nama blog-posts-get pada baris 23. Yang dilakukan pada fungsi assertQueue adalah mengecek apakah queue dengan name tersebut dan options yang di pass sudah ada atau belum. Semisal belum ada, maka fungsi tersebut akan membuat queue nya. Namun semisal ada tetapi tidak sesuai dengan options yang diberikan, fungsi tersebut bisa mengeluarkan exception.
  • Kita juga tentukan nilai prefetch pada channel tersebut, yang mana prefetch ini berarti jumlah maksimum message yang ditarik dari queue. Untuk reliabilitas maksimal, biasanya nilainya diset menjadi 1. (baris 24).
  • Pada baris 26, kita lakukan consume terhadap queue blog-posts-get dengan memasukkan callback function sebagai salah satu parameternya.
  • Ketika sudah mendapatkan result pada baris 29, kita perlu kirimkan hasilnya ke callback queue yang akan berbeda-beda dari setiap message yang masuk. Untuk pesan yang dikirimkan juga perlu dikonversi menjadi JSON dan kemudian dikonversikan lagi menjadi Buffer.
  • Pada baris 34, ketika pesan tersebut dirasa sudah selesai diproses semuanya dan sudah tidak dibutuhkan lagi, kita lakukan acknowledge sehingga pesan tersebut tidak masuk ke antrian lagi ketika callback function selesai dijalankan.

Implementasi HTTP Server

Berikut ini adalah implementasi script pada http-server yang dapat di tembak langsung oleh user. Data blog tidak disimpan di service ini karena berbeda domain, namun disimpan di service blog-posts-server.

Penjelasan code:

  • Connection dan channel RabbitMQ diinisiasi di awal pada baris 11–14, sehingga bisa di re-use selama runtime.
  • Ketika mendapatkan request pada URL dengan pattern blog/:id, inisiasi callback queue terlebih dahulu pada baris 21. Kita biarkan parameter pertamanya string kosong sehingga RabbitMQ akan melakukan generate random string secara otomatis untuk nama queue callback temporer ini.
  • Pada baris 23, kita buat random id untuk dijadikan sebagai correlation ID yang menjadi penanda setiap balasan message yang akan masuk nantinya.
  • Pada baris 29, kita lakukan consume callback queuenya. Hal ini perlu dilakukan sebelum mengirim message karena bisa saja proses selesai lebih cepat apabila request dikirimkan terlebih dahulu.
  • Pada baris 41, kita lakukan pengiriman message ke queue blog-posts-get dengan parameter ID yang dikonversi menjadi buffer.
  • Pada baris 31, kita lakukan pengecekan correlation ID yang didapat dari message apakah sesuai dengan yang kita kirimkan sebelumnya.
  • Setelah selesai diproses, pada baris 36 dan 37, kita lakukan cancel pada consumer tersebut dan lakukan delete pada queue temporary yang kita buat sebelumnya.

Running

Setelah selesai melakukan code pada kedua project, kita bisa langsung menjalankannya dengan node app.js pada masing-masing project. Namun disini saya menambahkan shortcut tersebut pada script start package.json.

Gambar 3. Hasil run program yang sudah dibuat

Kesimpulan

Penggunaan message broker untuk komunikasi antar microservices dapat mengatasi masalah kegagalan yang didapat dari menggunakan HTTP saja. Namun, optimasi code perlu dilakukan kembali sehingga penerapannya dapat menjadi lebih optimal.

Sekian tulisan pertama saya, jika ada salah kata mohon maaf. Atau jika anda menemukan bahwa metode yang saya bagikan masih kurang efisien, koreksi dan masukan akan sangat diapresiasi. :)

Referensi:

--

--