Back to Blog

Arsitektur Microservices: Kapan dan Bagaimana

Panduan pragmatis tentang arsitektur microservices, mencakup kapan masuk akal, bagaimana mendesain batasan service, dan bagaimana menghindari jebakan umum.

Pertanyaan Microservices

Setiap tim engineering yang berkembang pada akhirnya bertanya: haruskah kita beralih ke microservices? Jawaban jujurnya lebih bernuansa dari yang kebanyakan artikel sarankan. Microservices menyelesaikan masalah nyata, tapi memperkenalkan kompleksitas nyata. Arsitektur yang tepat bergantung pada ukuran tim, domain, dan kematangan operasional Anda.

Panduan ini membantu Anda memutuskan apakah microservices sesuai untuk situasi Anda, dan jika ya, bagaimana mengimplementasikannya dengan baik.

Kapan Microservices Masuk Akal

Alasan Baik untuk Mengadopsi

Deployment independen: Tim berbeda perlu men-deploy komponen mereka pada jadwal berbeda tanpa berkoordinasi dengan setiap tim lainnya.

Keberagaman teknologi: Beberapa bagian sistem Anda mendapat manfaat dari pilihan teknologi berbeda. Pipeline machine learning di Python, API real-time di Go, dan aplikasi web di Node.js masing-masing bisa menggunakan alat terbaik untuk tugasnya.

Scaling independen: Service pemrosesan pesanan Anda butuh 20 instance selama flash sale, tapi service katalog produk hanya butuh 2. Microservices memungkinkan Anda menskalakan setiap komponen secara independen.

Otonomi tim: Tim 5 hingga 8 orang memiliki seluruh service end-to-end: development, testing, deployment, dan monitoring. Model kepemilikan ini mengurangi overhead koordinasi.

Isolasi kegagalan: Saat mesin rekomendasi crash, seharusnya tidak menjatuhkan alur checkout.

Kapan Tetap Monolitik

Tim kecil: Jika seluruh tim engineering Anda di bawah 10 orang, monolit yang terstruktur baik hampir selalu pilihan yang lebih baik. Overhead koordinasi microservices melebihi manfaatnya.

Produk tahap awal: Saat Anda masih menemukan apa yang seharusnya dilakukan produk, microservices mengunci Anda ke batasan service terlalu dini. Bangun monolit dulu, lalu ekstrak service saat batasan stabil muncul.

Kemampuan operasional terbatas: Microservices membutuhkan monitoring canggih, logging, pipeline deployment, dan incident response. Jika Anda belum memilikinya, microservices akan menciptakan kekacauan.

Mendesain Batasan Service

Domain-Driven Design

Metode paling andal untuk mengidentifikasi batasan service berasal dari Domain-Driven Design (DDD). Setiap service selaras dengan bounded context: bagian dari domain bisnis dengan aturan konsistensi internalnya sendiri.

Untuk platform e-commerce:

Bounded Context:
├── Catalog Service
│   Memiliki: produk, kategori, harga
│   Data: deskripsi produk, gambar, harga

├── Order Service
│   Memiliki: pesanan, baris pesanan, status pesanan
│   Data: detail pesanan, status pemenuhan

├── Inventory Service
│   Memiliki: level stok, lokasi gudang
│   Data: kuantitas, reservasi, pergerakan

├── Customer Service
│   Memiliki: profil pelanggan, alamat
│   Data: info kontak, preferensi

├── Payment Service
│   Memiliki: pemrosesan pembayaran, refund
│   Data: metode pembayaran, catatan transaksi

└── Notification Service
    Memiliki: email, SMS, push notification
    Data: template, status pengiriman

Tes Batasan

Batasan service yang baik melewati pengecekan ini:

  1. Service bisa dikembangkan oleh satu tim (5 hingga 8 orang)
  2. Perubahan dalam service jarang membutuhkan perubahan di service lain
  3. Service memiliki data store sendiri yang tidak bisa diakses langsung oleh service lain
  4. API service stabil dan tidak sering berubah
  5. Service bisa di-deploy secara independen tanpa koordinasi

Jika perubahan sering membutuhkan pembaruan beberapa service secara bersamaan, service tersebut mungkin terlalu tightly coupled dan harus digabung atau batasannya digambar ulang.

Pola Komunikasi

Sinkron: REST dan gRPC

Untuk interaksi request-response di mana pemanggil membutuhkan jawaban segera:

// REST: Sederhana, mudah dibaca manusia, didukung luas
GET /api/products/12345
Response: { "id": "12345", "name": "Widget", "price": 25000 }

// gRPC: Protokol biner, lebih cepat, strongly typed
service ProductService {
  rpc GetProduct(ProductRequest) returns (Product);
  rpc ListProducts(ListRequest) returns (stream Product);
}

Gunakan REST untuk API publik dan gRPC untuk komunikasi service-to-service internal di mana performa penting.

Asinkron: Event-Driven

Untuk interaksi di mana pemanggil tidak membutuhkan respons segera:

// Order Service mempublikasikan event
{
  "event": "order.created",
  "timestamp": "2026-01-15T10:30:00Z",
  "data": {
    "orderId": "ORD-2026-001",
    "customerId": "CUST-456",
    "items": [
      { "productId": "PROD-789", "quantity": 2 }
    ],
    "totalAmount": 500000
  }
}

// Inventory Service subscribe dan mereservasi stok
// Payment Service subscribe dan menginisiasi pembayaran
// Notification Service subscribe dan mengirim email konfirmasi

Arsitektur event-driven memisahkan service secara temporal. Order Service tidak menunggu inventori, pembayaran, atau notifikasi selesai. Setiap service memproses event dengan kecepatannya sendiri.

Memilih Pola yang Tepat

SkenarioPolaAlasan
User meminta detail produkREST sinkronRespons segera dibutuhkan
Service perlu memvalidasi inventorigRPC sinkronPanggilan internal cepat
Pesanan dibuat, perlu memberitahu sistemEvent asinkronBanyak consumer, tanpa blocking
Sinkronisasi data antar serviceEvent asinkronEventually consistent bisa diterima
Workflow kompleks lintas servicePola sagaKoordinasi transaksi terdistribusi

Manajemen Data

Database Per Service

Setiap microservice memiliki datanya dan mengeksposnya hanya melalui API-nya. Tidak ada service yang langsung query database service lain:

Order Service      → orders_db (PostgreSQL)
Catalog Service    → catalog_db (PostgreSQL)
Search Service     → search_index (Elasticsearch)
Session Service    → sessions (Redis)
Analytics Service  → analytics_db (ClickHouse)

Isolasi ini berarti service bisa memilih teknologi database yang paling sesuai pola aksesnya. Ini juga berarti tidak ada service yang bisa merusak yang lain dengan memodifikasi data bersama.

Menangani Konsistensi Data

Di monolit, satu transaksi database memastikan konsistensi. Di microservices, Anda membutuhkan strategi berbeda:

Pola saga: Urutan transaksi lokal yang dikoordinasi melalui event. Jika langkah 3 gagal, transaksi kompensasi membatalkan langkah 1 dan 2.

Saga Pesanan:
1. Order Service: Buat pesanan (status: pending)
2. Payment Service: Proses pembayaran
   → Sukses: Lanjutkan
   → Gagal: Order Service membatalkan pesanan (kompensasi)
3. Inventory Service: Reservasi stok
   → Sukses: Order Service mengkonfirmasi pesanan
   → Gagal: Payment Service refund (kompensasi),
            Order Service membatalkan pesanan (kompensasi)

Event sourcing: Simpan urutan event, bukan state saat ini. Service manapun bisa membangun ulang tampilannya tentang data dengan memainkan ulang event.

Observability

Distributed Tracing

Saat request mengalir melalui lima service, Anda perlu melacaknya end-to-end:

Request: GET /api/orders/ORD-2026-001
Trace ID: abc-123-def-456

├── API Gateway (12ms)
├── Order Service (45ms)
│   ├── Database query (8ms)
│   └── Customer Service call (25ms)
│       └── Database query (5ms)
├── Inventory Service call (18ms)
│   └── Database query (6ms)
└── Total: 75ms

Tools distributed tracing (Jaeger, Zipkin, AWS X-Ray) menginstrumentasi service Anda untuk mempropagasi konteks trace lintas batasan service.

Logging Terpusat

Log dari semua service harus mengalir ke sistem terpusat. Sertakan trace ID di setiap pesan log agar Anda bisa mengorelasikan log lintas service untuk satu request:

{
  "timestamp": "2026-01-15T10:30:00.123Z",
  "service": "order-service",
  "traceId": "abc-123-def-456",
  "level": "info",
  "message": "Pesanan dibuat",
  "orderId": "ORD-2026-001",
  "customerId": "CUST-456"
}

Health Check dan Alerting

Setiap service membutuhkan:

  • Health check endpoint (/health) yang melaporkan status service
  • Metrics endpoint atau push-based metric collection (Prometheus)
  • Alert pada error rate, latensi, dan utilisasi resource
  • Runbook untuk skenario kegagalan umum

Jebakan Umum

Distributed Monolith

Jika setiap perubahan membutuhkan deployment terkoordinasi di beberapa service, Anda memiliki distributed monolith. Ini lebih buruk dari monolit biasa karena Anda memiliki semua kompleksitas sistem terdistribusi tanpa satupun manfaatnya.

Tanda-tanda distributed monolith:

  • Service berbagi database
  • Service harus di-deploy dalam urutan tertentu
  • Perubahan sering melintas beberapa service
  • Service memanggil satu sama lain secara sinkron dalam rantai panjang

Terlalu Banyak Service Terlalu Cepat

Memulai dengan 30 microservices saat Anda memiliki 15 engineer menciptakan kekacauan operasional. Overhead mengelola sebanyak itu service, database, pipeline deployment, dan dashboard monitoring membanjiri tim.

Mulai dengan monolith modular. Ekstrak service satu per satu saat batasan jelas muncul dan tooling operasional matang.

Mengabaikan Realitas Jaringan

Jaringan gagal. Latensi melonjak. Pesan terduplikasi atau hilang. Microservices yang tidak memperhitungkan ketidakandalan jaringan akan menunjukkan kegagalan aneh di production.

Setiap panggilan antar service membutuhkan:

  • Timeout (jangan pernah menunggu selamanya)
  • Retry dengan exponential backoff
  • Circuit breaker untuk mencegah kegagalan beruntun
  • Idempotensi untuk retry yang aman

Jalur Migrasi Pragmatis

Jika Anda beralih dari monolit ke microservices:

  1. Modularisasi monolit terlebih dahulu: Tetapkan batasan internal yang jelas, pisahkan layer akses data, definisikan API internal antar modul
  2. Bangun infrastruktur operasional: Monitoring, logging, CI/CD, orkestrasi container
  3. Ekstrak service pertama: Pilih sesuatu dengan batasan jelas dan coupling rendah ke sisanya. Notifikasi atau pencarian adalah titik awal umum.
  4. Belajar dan iterasi: Ekstraksi pertama akan mengungkap tantangan organisasional dan teknis. Atasi sebelum mengekstrak service berikutnya.
  5. Lanjutkan mengekstrak sesuai kebutuhan: Tidak setiap modul perlu menjadi service. Berhenti saat monolit yang tersisa bisa dikelola dan service yang diekstrak memberikan nilai.

Tujuannya bukan zero monolith. Tujuannya adalah arsitektur yang tepat untuk tim, produk, dan tahap pertumbuhan Anda.

Read in English English Version