Lewati ke konten
Backend Architecture Database

Mendesain SaaS Multi-Tenant di PostgreSQL Tanpa Menyesal

Tiga pendekatan multi-tenant di PostgreSQL — shared schema, schema-per-tenant, dan database-per-tenant — beserta trade-off yang saya temukan di produksi.

Wafik Ulinnuha

Backend Developer

2 menit baca

Multi-tenant adalah keputusan arsitektur yang sulit dibatalkan. Saat membangun Gatsu, kami harus memilih satu dari tiga model klasik di PostgreSQL: shared schema, schema-per-tenant, atau database-per-tenant. Setiap pilihan punya konsekuensi yang baru terasa setelah enam bulan.

Shared schema dengan kolom tenant_id

Pendekatan paling sederhana: satu skema, satu tabel, kolom tenant_id di setiap baris. Murah, cepat di-deploy, dan migrasi cukup dijalankan sekali. Cocok untuk fase MVP.

Tapi ada harga yang harus dibayar. Tanpa Row-Level Security (RLS), satu query salah filter bisa membocorkan data antar tenant. Indeks komposit harus selalu mengandung tenant_id, dan partisi berdasarkan tenant baru terasa perlu setelah jumlah baris menyentuh ratusan juta.

-- RLS minimal yang wajib dipasang
ALTER TABLE invoices ENABLE ROW LEVEL SECURITY;

CREATE POLICY tenant_isolation ON invoices
USING (tenant_id = current_setting('app.tenant_id')::uuid);

Schema-per-tenant

Setiap tenant mendapat schema sendiri (tenant_acme, tenant_globex). Isolasi lebih jelas, audit lebih mudah, backup per tenant juga sederhana. Trade-off-nya: setiap migrasi DDL harus dijalankan terhadap N schema. Pada 200 tenant, satu migrasi yang sebelumnya memakan 30 detik bisa menjadi 10 menit.

Kami memakai pola ini untuk modul akuntansi Gatsu, tempat data konsolidasi tenant tidak pernah dipakai bersama. Untuk tenant level, performa tetap stabil.

Database-per-tenant

Isolasi paling tegas. Backup, restore, dan compliance jadi mudah dijelaskan ke auditor. Namun jumlah koneksi membengkak cepat: 1 connection pool per tenant. Tanpa PgBouncer di tengah, server PostgreSQL akan kehabisan slot sebelum jam sibuk berakhir.

Mode transaction pooling di PgBouncer hampir selalu menjadi default kami. Kombinasinya dengan prepared statement perlu pengaturan, tapi efeknya signifikan: kami sanggup memuat 400+ tenant pada satu instance 4 vCPU.

Bagaimana saya memilih

  • Shared schema + RLS ketika tenant kecil dan banyak (≥ 1.000), data tidak sensitif, dan budget operasional rendah.
  • Schema-per-tenant ketika tenant menengah (10 — 500), butuh isolasi audit, dan migrasi DDL bisa diorkestrasi.
  • Database-per-tenant ketika tenant kelas enterprise yang minta kontrol penuh atas backup dan SLA.

Tidak ada model yang superior secara universal. Yang paling mahal bukan keputusan teknisnya, melainkan biaya berpindah ketika produk sudah berjalan. Lakukan estimasi pertumbuhan tenant dengan jujur sebelum menulis migration pertama.

Checklist sebelum commit pertama

  1. Tentukan model dan tulis ADR (Architecture Decision Record).
  2. Pasang test integrasi yang menjalankan query lintas-tenant dan memastikan isolasi.
  3. Aktifkan log_min_duration_statement dari hari pertama; query lintas-tenant biasanya pelan.
  4. Siapkan strategi backup yang sesuai dengan model — sebelum tenant nyata masuk.

Multi-tenant yang baik tidak terlihat. Ia muncul sebagai sistem yang tetap tenang ketika tenant ke-100 onboarding di tengah jam sibuk.

Topik

#Backend #Architecture #Database

Bagikan

Kembali ke daftar blog

Bacaan lanjutan

Bacaan lanjutan