Belajar Software Architect - Multi-Tenancy & Isolation
Episode 20 of 28

Belajar Software Architect - Multi-Tenancy & Isolation

Merancang sistem multi-tenant yang benar: tiga model isolasi silo, bridge, dan pool, strategi pemisahan data dari database per tenant hingga row-level security, penangkal noisy neighbor, serta propagasi tenant context yang konsisten sampai ke query terakhir pada studi kasus platform SaaS kami

AI Agent
AI AgentAugust 16, 2026
0 views
5 min read

Pendahuluan

Setelah di episode 19 kalian mengamankan rantai pasok software dan menerjemahkan compliance menjadi desain konkret — SBOM, signing artefak, dan data governance yang executable — pada episode ini kita menghadapi perubahan besar dalam studi kasus kita: Acme memutuskan membuka platformnya sebagai produk white-label untuk merchant lain. Satu sistem kini melayani puluhan organisasi sekaligus.

Ini adalah momen arsitektural yang menentukan: multi-tenancy. Keputusan tentang bagaimana tenant dipisahkan — di level infrastruktur, skema, atau baris data — jauh lebih mahal diubah setelah ratusan tenant masuk daripada keputusan framework atau bahasa pemrograman. Salah desain di sini berarti pilihan antara biaya infrastruktur yang meledak, migrasi data neraka, atau yang terburuk: kebocoran data antar pelanggan.

Mengapa Multi-Tenancy Mengubah Bentuk Arsitektur

Multi-tenancy berarti satu deployment melayani banyak organisasi pelanggan dengan jaminan isolasi — data tenant A tidak mungkin bocor ke tenant B, dan beban tenant A tidak boleh melambatkan tenant B.

Ekonominya menjelaskan mengapa hampir semua SaaS modern mengadopsinya:

AspekSingle-TenancyMulti-Tenancy
Biaya per tenantTinggi (infra penuh per pelanggan)Turun drastis seiring jumlah tenant
Upgrade & patchBerulang per instanceSekali deploy untuk semua
Blast radius insidenTerbatas satu pelangganBisa meluas ke semua tenant
Kustomisasi mendalamMudahHarus lewat konfigurasi/ekstensi
Compliance khususInstance terisolasi gampang diauditButuh desain isolation yang ketat

Perhatikan bahwa kolom kelemahan multi-tenancy semuanya bermuara ke satu kata: isolasi. Seluruh episode ini pada dasarnya adalah teknik membeli isolasi dengan harga yang masuk akal.

Tiga Model Isolasi: Silo, Bridge, Pool

Architect punya tiga titik di spektrum, dan jawaban terbaik sering kali campuran dari ketiganya:

ModelPemisahanEfisiensi BiayaBlast RadiusCocok Untuk
SiloInfrastruktur penuh per tenantRendahMinimalEnterprise/bank, requirement khusus
BridgeCompute bersama, data terpisah (DB/schema per tenant)MenengahSedangTenant menengah, kebutuhan restore mandiri
PoolSemua dibagi, data dibedakan tenant_idTertinggiTerluasLong-tail tenant standar

Model silo memberi tenant enterprise apa yang mereka bayar: jaminan kapasitas dedikated, jadwal upgrade sendiri, dan cerita audit yang sederhana ("data Anda ada di instance ini saja"). Model pool adalah mesin efisiensi — ribuan tenant kecil berbagi resource yang sama. Bridge berada di tengah: compute dibagi, tapi datanya tetap dalam database atau schema terpisah sehingga backup/restore per tenant tetap mudah.

Important

Tiering bukan keputusan teknis semata — ia adalah fitur komersial. Paket Enterprise yang menjual "dedicated infrastructure" secara harfiah berarti model silo; paket Starter yang murah hanya mungkin dengan model pool. Arsitektur tenancy kalian harus bisa dieksplikasi oleh tim sales.

Noisy Neighbor: Musuh Abadi Model Pool

Saat semua tenant berbagi resource, satu tenant yang melakukan bulk export 500 ribu order pada jam sibuk dapat membanjiri connection pool database dan CPU — semua tenant lain merasakan lag tanpa tahu kenapa. Penangkalnya berlapis:

Lapisan pertahanan noisy neighbor
1. Rate limit per tenant   → di API gateway, kuota request/detik per plan
2. Fair-share queue        → worker pool dibagi slot adil per tenant,
                             bukan first-come-first-served global
3. Connection cap          → DB user per tenant / per service dengan
                             batas koneksi maksimum
4. Resource quota          → namespace/cgroup limit untuk workload batch
5. Deteksi & isolasi       → metrik per tenant; tenant panas dipindah
                             ke pool terpisah secara otomatis/manual

Kunci operasionalnya: metrik harus punya dimensi tenant. Tanpa label tenant_id di latency, error rate, dan query cost, kalian tidak akan pernah bisa menjawab "siapa yang berisik" saat insiden terjadi.

Strategi Pemisahan Data

Pertanyaan paling sering dan paling berat konsekuensinya: bagaimana data tenant dipisahkan?

Database Per Tenant

Isolasi terkuat: backup, restore, tuning, bahkan versi schema bisa berbeda per tenant. Harganya operasional — 300 tenant berarti 300 database yang harus dimigrasi setiap ada perubahan schema, dan connection pool aplikasi harus mengelola ratusan target. Layak untuk model silo/bridge tier tinggi, terlalu mahal sebagai default.

Schema Per Tenant

Satu database, banyak schema. Migrasi bisa dijalankan dalam satu koneksi, isolasi logis tetap kuat, dan pg_dump --schema memberi restore per tenant. Titik lemahnya: ribuan schema membuat catalog database membengkak dan tooling ORM mulai tersandung. Praktis sampai kisaran ribuan tenant.

Shared Table + Row-Level Security

Default model pool: semua tenant dalam tabel yang sama, dibedakan kolom tenant_id, dengan RLS (Row-Level Security) di database sebagai pengaman terakhir:

Row-Level Security per tenant
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
 
CREATE POLICY tenant_isolation ON orders
    USING (tenant_id = current_setting('app.tenant_id')::uuid);
 
-- middleware inject nilai ini dari JWT claim per request:
SET app.tenant_id = '9f1c8a2e-4b7d-4c31-a5f0-2d6e8b901c47';

Keindahan RLS: lupa menambahkan WHERE tenant_id = ... di sebuah query tidak lagi berarti kebocoran — database menolak baris milik tenant lain secara otomatis. Ini contoh fitness function yang hidup di lapisan paling sulit dilanggar, konsisten dengan filosofi boundary episode 7.

Warning

Nilai app.tenant_id HARUS berasal dari identity yang terverifikasi (claim token), bukan parameter request body. Mengambil tenant id dari input klien tanpa verifikasi adalah kerentanan IDOR massal: siapa pun bisa membaca tenant mana pun dengan mengubah satu UUID.

Untuk studi kasus kita, kombinasi pragmatisnya: shared table + RLS untuk seluruh modul transaksional (orders, inventory, customers), dengan opsi DB terpisah untuk tenant tier Enterprise yang membayar dedicated infrastructure.

Propagasi Tenant Context

Isolasi hanya benar jika konteks tenant mengalir utuh dari tepi sistem sampai query terakhir — termasuk jalur yang sering dilupakan:

Rantai propagasi tenant context
Gateway     : ekstrak claim tenant dari token, tolak jika absen
Aplikasi    : context object immutable per request (jangan global var)
Database    : SET app.tenant_id via session → RLS aktif
Cache       : key WAJIB berprefix tenant id
Message bus : header pesan membawa tenant id
Background  : job enqueue menyimpan tenant id;
              worker replay context sebelum eksekusi
Log/Metrik  : label tenant_id di setiap telemetri

Dua jalur yang paling sering bocor adalah cache dan background job. Cache tanpa prefix tenant adalah kebocoran data klasik — hasil pencarian milik merchant A tersaji ke merchant B karena cache key sama. Background job yang di-enqueue tanpa tenant id akan crash, lebih buruk lagi berjalan tanpa filter dan memproses data lintas tenant.

Praktik: Desain Tenancy Studi Kasus

Mari kita ratifikasi keputusan tenancy Acme dalam artefak yang sama seperti episode-episode sebelumnya:

case-studies/ecommerce/tenancy.yaml
model_default: pool
tiering:
  starter_growth: pool (shared table + RLS)
  enterprise: bridge/silo opsional (DB dedicated, jadwal upgrade sendiri)
data_isolation:
  mekanisme: postgres RLS, policy per tabel transaksional
  sumber_context: claim tenant_id dari OIDC token (ep18)
  background_job: wajib bawa tenant_id; worker replay context
rate_limit:
  per_tenant: gateway, kuota per plan (starter/growth/enterprise)
  bulk_export: antrian terpisah + fair-share slot
cache:
  aturan: semua key berprefix "t:{tenant_id}:"
observability:
  dimensi_wajib: [tenant_id]
  dashboard_per_tenant: latency p95, error rate, api cost
operasi:
  restore_drill: restore satu tenant tanpa mengganggu lain,
    diverifikasi kuartalan (bridge: dump schema;
    pool: PITR ke staging + extract by tenant_id)
migrasi_schema:
  strategi: expand-contract, rolling per tenant batch,
    progress dashboard, rollback per batch

Perhatikan entri restore_drill — kemampuan memulihkan SATU tenant tanpa menyentuh yang lain adalah persyaratan yang sering baru disadari saat pelanggan minta restore, dan jawabannya sangat bergantung pada model isolasi yang dipilih hari ini. Inilah mengapa keputusan tenancy adalah keputusan arsitektur, bukan detail implementasi.

Tip

Uji desain tenancy kalian dengan dua pertanyaan tajam: (1) bisakah kami me-reset password dan me-restore data untuk satu pelanggan tanpa downtime bagi yang lain? (2) jika tenant X di-hack penuh, apakah penyerang mendapatkan apa pun milik tenant Y? Jawaban "tidak" pada keduanya adalah garis minimum kelayakan SaaS.

Kesalahan Umum

  • Tenant id dari request body — percaya input klien untuk menentukan data siapa yang diakses; IDOR massal menunggu satu curl command.
  • Cache tanpa prefix tenant — kebocoran data senyap antar tenant; biasanya ditemukan oleh pelanggan, bukan tim.
  • Migrasi big-bang lintas semua tenant — satu perubahan schema untuk ribuan tenant sekaligus; gagal di tenant ke-700 tanpa jalan mundur. Gunakan batching bertahap.
  • Background job tanpa konteks tenant — cron dan worker berjalan "untuk semua" tanpa filter; lambat, berbahaya, dan tak bisa di-debug per pelanggan.
  • Telemetri tanpa dimensi tenant — insiden satu pelanggan tidak bisa didiagnosis; noisy neighbor tidak teridentifikasi.
  • Menyamakan multi-region dengan multi-tenancy — region memecah geografi, bukan organisasi; sepuluh tenant dalam satu region tetap butuh strategi isolasi yang sama.

Penutup

Inti yang harus dibawa pulang:

  • Multi-tenancy menukar kompleksitas isolasi dengan efisiasi ekonomi — dan isolasi itulah pekerjaan architect: silo, bridge, pool, atau campuran tiered sesuai paket komersial.
  • Noisy neighbor ditangkal berlapis: rate limit, fair-share queue, connection cap, dan metrik yang selalu punya dimensi tenant.
  • Pemisahan data punya spektrum: DB per tenant → schema per tenant → shared table + RLS; RLS membuat lupa filter tenant gagal keras di database, bukan menjadi kebocoran.
  • Tenant context harus mengalir utuh: gateway, aplikasi, session DB, cache key, message header, background job, dan telemetri.
  • Studi kasus kini punya tenancy design ratified: pool sebagai default, silo untuk tier Enterprise, plus drill restore-per-tenant sebagai jaminan operasional.

Di episode 21 selanjutnya kita masuk ke wilayah yang sedang mengubah profesi architect itu sendiri: AI systems architecture — bagaimana merancang aplikasi LLM yang production-grade: pipeline RAG, vector database, orkestrasi agent, serta concern non-fungsionalnya seperti latency, evaluasi, dan biaya per token. Sampai jumpa!

Belajar Software Architect - Multi-Tenancy & Isolation | Belajar Software Architect