Service Mesh — System Design

Service Mesh adalah lapisan infrastruktur yang mengatur komunikasi antar microservice, memindahkan logika networking (retry, circuit breaker, observability)…

Service mesh adalah lapisan infrastruktur yang mengurus komunikasi antar service (timeout, retry, enkripsi, dan pencatatan) tanpa mengubah kode aplikasinya. Bayangin gedung kantor dengan banyak divisi, dan tiap divisi punya resepsionis sendiri di pintunya. Semua surat keluar-masuk lewat resepsionis: dia mengecek kartu identitas pengirim, mengirim ulang surat yang mental, berhenti menunggu balasan yang kelamaan, dan mencatat semuanya di buku tamu. Staf divisi cukup menulis isi suratnya. Buku aturan untuk semua resepsionis datang dari satu kantor pusat. Resepsionis itu sidecar proxy, kantor pusatnya control plane.

🧪 Tebakan cepat: bayar-2, satu dari tiga pod service bayar, menjawab 503 untuk setiap request, jadi sepertiga pembayaran gagal. Bisakah error-nya jadi nol tanpa mengubah satu baris pun di kode order? Tebak dulu, jawabannya ada di bagian "Retry dan timeout pindah ke config".

TiketNada sekarang punya empat service

TiketNada, aplikasi tiket konser kita, sudah dipecah jadi microservices yang jalan di Kubernetes (dasarnya ada di lesson Kubernetes Basics dan Microservices Architecture di track DevOps):

Service Bahasa Pod Tugasnya
order Node.js 2 menerima pesanan
bayar Go 3 memotong kartu
tiket Java 2 memegang kursi
notif Python 1 mengirim e-tiket

Tiap panggilan antar service butuh hal yang sama: timeout (batas menunggu), retry (coba lagi kalau gagalnya sementara), TLS (enkripsi, supaya isi request gak bisa dibaca orang yang menyadap jaringan), dan metrics (berapa request, berapa yang error, berapa lama). Kalau semuanya ditulis di kode, itu 4 fitur × 4 bahasa = 16 implementasi, dengan library berbeda dan bug berbeda. Mengubah aturan retry berarti mengubah dan men-deploy ulang empat service.

Sidecar: proxy di samping tiap service

Service mesh memindahkan urusan itu keluar dari kode. Tiap pod mendapat container tambahan, sidecar proxy, yang jalan di sebelah container aplikasinya. Aturan iptables di dalam pod membelokkan semua traffic masuk dan keluar ke proxy itu. Jadi saat order memanggil http://bayar:8080/charges dengan HTTP biasa, jalannya begini:

order → sidecar order → (mTLS) → sidecar bayar → bayar

Semua sidecar bersama-sama disebut data plane: merekalah yang benar-benar memegang traffic. Yang mengatur mereka disebut control plane: dia membagikan aturan (route, retry, timeout) dan sertifikat ke setiap sidecar. Di Istio, control plane-nya bernama istiod dan sidecar-nya Envoy, proxy open-source buatan Lyft yang juga dipakai banyak mesh lain. Linkerd memakai proxy-nya sendiri yang ditulis dengan Rust. Menyalakan Istio di namespace TiketNada:

kubectl label namespace tiketnada istio-injection=enabled
kubectl rollout restart deployment -n tiketnada

Retry dan timeout pindah ke config

Aturan traffic ditulis sebagai YAML, lalu control plane mengirimnya ke semua sidecar. Ini aturan untuk semua panggilan ke bayar:

apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: bayar
  namespace: tiketnada
spec:
  hosts:
  - bayar
  http:
  - route:
    - destination:
        host: bayar
    timeout: 2s
    retries:
      attempts: 2
      perTryTimeout: 500ms
      retryOn: gateway-error,connect-failure,refused-stream

Ini 6 pembayaran, pesanan #1001 sampai #1006, yang dibagi bergiliran ke tiga pod sementara bayar-2 menjawab 503. Angkanya model contoh: jaringan 10 ms sekali jalan, memotong kartu 120 ms, bayar-2 menolak dalam 2 ms, sidecar menambah 1 ms per panggilan, jeda sebelum retry 25 ms.

Pesanan Pod Tanpa mesh Dengan mesh
#1001, #1004 bayar-1 201 dalam 140 ms 201 dalam 141 ms
#1002, #1005 bayar-2 503 dalam 22 ms 503 (23 ms), jeda 25 ms, retry ke bayar-3: 201, total 189 ms
#1003, #1006 bayar-3 201 dalam 140 ms 201 dalam 141 ms

Tanpa mesh, 2 dari 6 pembayaran gagal. Dengan mesh, 0 gagal, dan kode order gak berubah satu baris pun. Itu jawaban tebakannya: bisa, karena yang me-retry adalah sidecar, bukan kode. Kalau bayar-2 bukan error tapi macet 30 detik, perTryTimeout memotongnya di 500 ms dan retry ke pod sehat: selesai dalam 500 + 25 + 141 = 666 ms, bukan 30.020 ms.

Tanpa VirtualService pun, Istio sudah me-retry 2 kali secara default, tapi gak memasang timeout sama sekali. Timeout harus kamu tulis sendiri.

mTLS: tiap service punya KTP

Di HTTPS biasa, cuma server yang menunjukkan sertifikat. Di mTLS (mutual TLS), dua-duanya menunjukkan sertifikat. Control plane bertindak sebagai CA (pihak yang menerbitkan sertifikat): tiap pod dapat sertifikat berisi identitasnya, misalnya spiffe://cluster.local/ns/tiketnada/sa/order, yang berlaku 24 jam dan diganti otomatis. Hasilnya dua: isi request terenkripsi (penyadap cuma melihat byte acak), dan bayar tahu pasti pemanggilnya order, bukan pod lain yang menyamar.

Istio mulai di mode PERMISSIVE: sidecar ke sidecar sudah mTLS, tapi request polos dari pod tanpa sidecar masih diterima, supaya pemasangan mesh gak memutus apa-apa. Setelah semua pod punya sidecar, kunci dengan STRICT:

apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
  name: default
  namespace: tiketnada
spec:
  mtls:
    mode: STRICT

Lalu tes dari pod debug yang gak punya sidecar:

$ kubectl exec debug -n tiketnada -- curl -s -o /dev/null -w "%{http_code}\n" http://bayar:8080/healthz
000
command terminated with exit code 56

Mau lebih ketat lagi, misalnya "cuma order yang boleh memanggil bayar"? Itu tugas AuthorizationPolicy, yang memakai identitas dari sertifikat tadi.

Harga sebuah mesh

Mesh gak gratis. Dengan angka model contoh untuk 8 pod TiketNada:

Istio sekarang juga punya ambient mode: tanpa sidecar per pod. mTLS diurus satu proxy per node (ztunnel), dan proxy untuk retry dan routing (waypoint) dipasang cuma untuk service yang butuh. Lebih hemat, idenya sama: urusan jaringan keluar dari kode.

🎯 Kapan pakai mesh, kapan jangan

⚠️ Jebakan yang sering ketemu

TL;DR: Service mesh adalah lapisan infrastruktur yang menyuntikkan sidecar proxy (di Istio: Envoy) ke setiap pod, sehingga semua komunikasi antar service lewat proxy itu tanpa mengubah kode aplikasi. Sidecar-sidecar itu data plane; control plane (istiod) membagikan aturan dan sertifikat. Keuntungan utamanya: retry, timeout, mTLS, dan metrics ditangani konsisten di infrastruktur, gak bergantung pada bahasa atau library tiap service. Retry dan timeout ditulis di VirtualService (attempts, perTryTimeout, timeout); dengan bayar-2 error, pembayaran TiketNada gagal 0 dari 6 tanpa mengubah kode order. mTLS memberi tiap service identitas; mode STRICT menolak pod tanpa sidecar (000, exit code 56). Harganya RAM per sidecar, sedikit latency, dan satu sistem lagi untuk dirawat, jadi mesh untuk banyak service lintas bahasa, bukan untuk 3 service. Retry di mesh tetap butuh idempotency untuk request yang mengubah data.

Yang akan kamu pelajari