Membuat Microservice dengan ZeroMQ

By | December 30, 2025
505 Views

Dalam dunia sistem terdistribusi dan microservice, komunikasi antar layanan menjadi faktor kunci. Banyak pengembang langsung memilih HTTP/REST, gRPC, atau message broker seperti RabbitMQ. Namun, ada satu teknologi yang sering dipakai di sistem performa tinggi tetapi jarang dibahas secara populer, yaitu ZeroMQ (ØMQ).

ZeroMQ bukan server, bukan broker, melainkan library messaging yang memberi kita kontrol penuh atas bagaimana microservice saling berkomunikasi. Artikel ini akan membahas bagaimana ZeroMQ dapat digunakan untuk membangun arsitektur microservice yang cepat, skalabel, dan fleksibel.

Apa itu ZeroMQ?

ZeroMQ adalah asynchronous messaging library yang bekerja di atas TCP, IPC, atau in-process communication. ZeroMQ menyediakan berbagai messaging pattern yang bisa langsung dipakai tanpa harus membangun protokol sendiri dari nol.

Ciri utama ZeroMQ:

  • Tidak membutuhkan server pusat
  • Ringan dan sangat cepat
  • Mendukung komunikasi asynchronous
  • Cocok untuk sistem paralel dan terdistribusi

ZeroMQ banyak dipakai di:

  • Jupyter Notebook (komunikasi kernel)
  • Sistem Computer Vision & AI
  • High Performance Computing (HPC)
  • Trading system dan data streaming

Konsep Microservice dengan ZeroMQ

Pada microservice tradisional, setiap service berkomunikasi lewat HTTP endpoint. Dengan ZeroMQ, pendekatannya sedikit berbeda:

  • Setiap service adalah process mandiri
  • Komunikasi dilakukan lewat socket ZeroMQ
  • Routing dan skalabilitas dikontrol oleh arsitektur

Contoh sederhana:

Client → Image Service → Result

Namun di ZeroMQ, arsitektur bisa dikembangkan menjadi:

Client → ROUTER → DEALER → Worker Service

Messaging Pattern yang Penting

1. REQ–REP (Request–Reply)

Digunakan untuk komunikasi sederhana:

  • Client mengirim request
  • Server membalas reply

Cocok untuk:

  • API sederhana
  • Prototyping

Keterbatasan:

  • Tidak fleksibel untuk paralel
  • Harus strict request–reply

2. ROUTER–DEALER (Direkomendasikan)

Ini adalah pola utama untuk microservice ZeroMQ.

Keunggulan:

  • Mendukung banyak client
  • Reply bersifat private (berdasarkan identity)
  • Bisa asynchronous
  • Mudah diskalakan

Pola ini memungkinkan server mengetahui client mana yang mengirim request tanpa client lain mengetahuinya.

3. PUSH–PULL (Pipeline)

Digunakan untuk job queue satu arah:

  • PUSH: kirim job
  • PULL: worker ambil job

Cocok untuk:

  • Batch processing
  • Pipeline data

Contoh Microservice: Image Processing

Arsitektur

Client → ROUTER → DEALER → Image Worker
  • Client mengirim gambar
  • Worker memproses gambar (grayscale, edge, OCR, dll)
  • Hasil dikirim kembali ke client yang benar

Setiap worker berjalan sebagai service terpisah, sehingga benar-benar memenuhi konsep microservice.

Paralelisme dan Skalabilitas

Salah satu keunggulan ZeroMQ adalah paralelisme alami.

  • Worker bisa dijalankan sebanyak core CPU
  • Tidak perlu tahu jumlah client
  • Beban otomatis dibagi

Jika beban meningkat:

  • Jalankan worker baru
  • Tidak perlu restart sistem

Hal ini sangat cocok untuk:

  • AI inference server
  • Image & video processing
  • Sistem dengan lonjakan trafik

Monitoring Queue

ZeroMQ tidak menyediakan queue monitoring secara default. Namun ini bisa diatasi dengan:

  • zmq.proxy() + capture socket
  • Menghitung job masuk vs job selesai
  • Estimasi panjang antrian

Dengan pendekatan ini, kita bisa:

  • Mendeteksi bottleneck
  • Menentukan kapan menambah worker
  • Membuat auto-scaling sederhana

Keamanan Microservice ZeroMQ

Secara default, ZeroMQ tidak aman. Namun ZeroMQ menyediakan mekanisme keamanan yang kuat:

CurveZMQ

  • Enkripsi end-to-end
  • Public–private key
  • Client tidak dikenal otomatis ditolak

Best Practice Keamanan

  • Gunakan CurveZMQ
  • Jangan expose port ke publik
  • Worker gunakan IPC (lokal)
  • Batasi ukuran pesan
  • Validasi payload

Dengan konfigurasi benar, ZeroMQ bisa setara aman dengan HTTPS.

ZeroMQ vs Message Broker

Aspek ZeroMQ RabbitMQ
Tipe Library Broker
Latency Sangat rendah Lebih tinggi
Persistence Tidak ada Ada
Monitoring Manual Built-in
Fleksibilitas Sangat tinggi Terbatas

ZeroMQ unggul untuk real-time microservice, sementara RabbitMQ unggul untuk reliability dan durability.

Kapan ZeroMQ Cocok untuk Microservice?

Gunakan ZeroMQ jika:

  • Membutuhkan latency rendah
  • Beban komputasi tinggi
  • Microservice bersifat stateless
  • Data besar (gambar, array, tensor)

Hindari ZeroMQ jika:

  • Tidak boleh kehilangan pesan
  • Butuh audit log & persistence
  • Ingin solusi siap pakai tanpa banyak coding

 

Contoh Kasus

Kita akan membuat contoh penggunaan ZeroMQ untuk

2 client mengirim gambar → server memproses → hasil dikirim balik ke client

Model ini mirip chat, tapi isi pesannya data gambar.

Arsitektur (gampang dulu)

Pola ZeroMQ yang cocok: REQ – REP

Client A ─┐
          ├──> Server (olah gambar)
Client B ─┘
  • Client = kirim gambar
  • Server = terima → proses → balas hasil

1. Server ZeroMQ (image processor)

simpan dengan nama server.py

import zmq
import cv2
import numpy as np
import pickle

context = zmq.Context()
socket = context.socket(zmq.REP)
socket.bind("tcp://*:5555")

print("Server siap di port 5555...")

while True:
    # terima data
    data = socket.recv()

    # deserialize
    img = pickle.loads(data)

    # === PROSES GAMBAR (contoh: grayscale + edge) ===
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    edges = cv2.Canny(gray, 100, 200)

    # serialize hasil
    reply = pickle.dumps(edges)

    socket.send(reply)

 

2. Client ZeroMQ (pengirim gambar)

simpan dengan nama client.py

import zmq 
import cv2 
import pickle 
context = zmq.Context() 
socket = context.socket(zmq.REQ) 
socket.connect("tcp://localhost:5555") 
# baca gambar 
img = cv2.imread("gambar.jpg")
# kirim ke server 
socket.send(pickle.dumps(img)) 
# terima hasil 
result = pickle.loads(socket.recv()) 
# tampilkan 
cv2.imshow("Hasil dari server", result) 
cv2.waitKey(0) 
cv2.destroyAllWindows()

 

3. Jalankan 2 client sekaligus

Buka 3 terminal:

Terminal 1 (server)

python server.py

Terminal 2 (client A)

python client.py

Terminal 3 (client B)

python client.py

Server akan melayani client satu per satu secara bergantian

Membuat Server bekerja dengan Beberapa Client

Server harus tahu “alamat/identitas” tiap client, lalu membalas langsung ke client itu saja.

Di ZeroMQ, ini tidak bisa dengan REP/REQ biasa kalau kamu mau kontrol penuh. Solusinya: ROUTER ↔ DEALER.

Setiap client punya ID unik
Server:

  • Menerima pesan + identity pengirim

  • Membalas pakai identity itu

Client lain tidak akan menerima pesan tersebut. Maka arsitektur yang benar adalah

Client A (ID=A) ──┐
                  ├──> ROUTER Server ── balas ke A
Client B (ID=B) ──┘                    ── balas ke B

Private reply, bukan broadcast

Mari kita coba

1. Server (ROUTER)

server.py

import zmq
import cv2
import numpy as np
import pickle

context = zmq.Context()
socket = context.socket(zmq.ROUTER)
socket.bind("tcp://*:5555")

print("Server ROUTER siap...")

while True:
    # ROUTER menerima: [identity][empty][data]
    identity, empty, data = socket.recv_multipart()

    print(f"Pesan dari client: {identity}")

    img = pickle.loads(data)

    # proses gambar
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    reply = pickle.dumps(gray)

    # balas hanya ke client ini
    socket.send_multipart([
        identity,
        b"",
        reply
    ])

2. Client (DEALER)

client.py

import zmq
import cv2
import pickle
import uuid

context = zmq.Context()
socket = context.socket(zmq.DEALER)

# identity unik tiap client
client_id = f"client-{uuid.uuid4()}".encode()
socket.setsockopt(zmq.IDENTITY, client_id)

socket.connect("tcp://localhost:5555")

print("Client ID:", client_id)

img = cv2.imread("gambar.jpg")

# kirim
socket.send(pickle.dumps(img))

# terima balasan (PRIVATE)
result = pickle.loads(socket.recv())

cv2.imshow("Hasil dari server", result)
cv2.waitKey(0)
cv2.destroyAllWindows()

Server multi-task (advanced)

Mari kita perluas dengan server yang multi tasking.

  • Banyak client kirim gambar

  • Server memproses secara paralel

  • Balasan hanya ke client pengirim

  • Tidak saling tahu

Desainnya seperti berikut

Client A ─┐
Client B ─┼──> [ROUTER] ──> [DEALER] ──> Worker 1
Client C ─┘                       ├──> Worker 2
                                  └──> Worker 3

Peran:

  • ROUTER (frontend) → tahu identity client

  • DEALER (backend) → load balancing ke worker

  • Worker → proses gambar

  • Reply balik lewat jalur yang sama

1. Server Utama (Broker)

server.py

import zmq

context = zmq.Context()

# frontend: client <-> server
frontend = context.socket(zmq.ROUTER)
frontend.bind("tcp://*:5555")

# backend: server <-> worker
backend = context.socket(zmq.DEALER)
backend.bind("ipc://backend.ipc")

print("Server broker jalan...")

# otomatis forward bolak-balik
zmq.proxy(frontend, backend)

Server ini tidak mengolah data, cuma mengatur lalu lintas

2. Worker (Proses Paralel)

📌 worker.py

import zmq
import cv2
import pickle
import time

context = zmq.Context()
socket = context.socket(zmq.DEALER)
socket.connect("ipc://backend.ipc")

print("Worker siap...")

while True:
    # terima multipart:
    # [client_id][empty][data]
    client_id, empty, data = socket.recv_multipart()

    img = pickle.loads(data)

    # simulasi proses berat
    time.sleep(2)

    # proses gambar
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    reply = pickle.dumps(gray)

    # kirim balik ke client yang benar
    socket.send_multipart([
        client_id,
        b"",
        reply
    ])

3. Client (DEALER, private)

📌 client.py

import zmq
import cv2
import pickle
import uuid

context = zmq.Context()
socket = context.socket(zmq.DEALER)

client_id = f"client-{uuid.uuid4()}".encode()
socket.setsockopt(zmq.IDENTITY, client_id)

socket.connect("tcp://localhost:5555")
print("Client:", client_id)

img = cv2.imread("gambar.jpg")

socket.send(pickle.dumps(img))

result = pickle.loads(socket.recv())

cv2.imshow("Hasil", result)
cv2.waitKey(0)
cv2.destroyAllWindows()

4. Cara Menjalankan (INI PENTING)

Terminal 1 → Server

python server.py

Terminal 2,3,4 → Worker (bebas mau berapa)

python worker.py
python worker.py
python worker.py

Terminal lain → Banyak client

python client.py
python client.py
python client.py
  • Worker otomatis dibagi beban
  • Client tidak saling tahu
  • Reply tepat sasaran