Çok kiracılı mimaride veri izolasyonu: üç yaklaşım, üç fatura
Ayrı veritabanı, ayrı şema ve satır düzeyi güvenlik arasındaki seçim bir teknoloji tercihi değil, bir risk ve maliyet kararıdır. Üçünü de kullandığımız projelerden notlar.
Bir SaaS ürününde ilk günden verilen ve en zor geri alınan karar, kiracı verilerinin nasıl ayrılacağıdır. Üç ana yol var ve hiçbiri diğerinden mutlak olarak iyi değil.
Yol 1: Kiracı başına veritabanı
Her kiracı kendi veritabanında durur.
Güçlü yanı: İzolasyon fiziksel. Bir sorgu hatası başka kiracının verisine erişemez, çünkü bağlantı bile yok. Yedekleme, geri yükleme ve veri silme kiracı bazında yapılabilir — KVKK ve GDPR talepleri için bu ciddi bir kolaylık.
Zayıf yanı: Şema göçü. Beş yüz kiracınız varsa her sürümde beş yüz veritabanında göç çalıştırırsınız. Bir tanesi yarıda kalırsa karma sürümlü bir sistemle uğraşırsınız.
Ne zaman seçiyoruz: Kiracı sayısı düşük (birkaç yüz), kiracı başına veri hacmi yüksek ve müşteriler sözleşmede fiziksel ayrım istiyorsa.
Yol 2: Ortak veritabanı, kiracı başına şema
Tek veritabanı, kiracı başına bir PostgreSQL şeması.
Güçlü yanı: Göç hâlâ toplu çalıştırılabilir ama izolasyon mantıksal olarak nettir. search_path ile bağlantı başına doğru şemaya yönlendirirsiniz.
Zayıf yanı: Şema sayısı büyüdükçe katalog tabloları şişer; birkaç bin şemadan sonra bağlantı kurulum süresi ve planlayıcı maliyeti hissedilir hale gelir.
Ne zaman seçiyoruz: Orta ölçekli kiracı sayısı (yüzler), göç sıklığı yüksek ve kiracı başına özelleştirilmiş tablolara ihtiyaç varsa.
Yol 3: Ortak tablo, satır düzeyi güvenlik
Tüm kiracılar aynı tabloda, tenant_id sütunuyla ayrılır ve PostgreSQL'in satır düzeyi güvenliği (RLS) uygulanır.
alter table invoices enable row level security;
create policy tenant_isolation on invoices
using (tenant_id = current_setting('app.tenant_id')::uuid);
Güçlü yanı: Tek şema, tek göç, en düşük işletme maliyeti. Binlerce kiracıya ölçeklenir.
Zayıf yanı: İzolasyon tamamen doğru yapılandırmaya bağlıdır. app.tenant_id ayarlanmadan açılan tek bir bağlantı, tüm politikayı devre dışı bırakabilir. Ayrıca tablo sahibi rolü varsayılan olarak RLS'i atlar — bu ayrıntıyı kaçırmak, izolasyonu görünürde var ama fiilen yok hale getirir.
Ne zaman seçiyoruz: Kiracı sayısı yüksek, kiracı başına veri hacmi düşük ve ürün standart (kiracıya özel şema yok).
RLS seçiyorsak aldığımız önlemler
Üçüncü yolu en sık seçiyoruz, çünkü işletme maliyeti belirgin biçimde düşük. Ancak şu dört önlem olmadan üretime almıyoruz:
- Uygulama rolü asla tablo sahibi olmaz. Sahip rol yalnızca göç için kullanılır ve uygulamaya verilmez.
FORCE ROW LEVEL SECURITYaçıktır. Böylece sahip rol de politikaya tabi olur.- Bağlantı havuzunda kiracı bağlamı zorunludur. Havuzdan alınan her bağlantı, sorgu çalıştırılmadan önce
set_configile etiketlenir; etiketsiz bağlantı üzerinden sorgu çalıştırmaya kalkışan kod, geliştirmede hata fırlatır. - Sızıntı testi CI'da koşar. İki kiracı yaratılır, birinin bağlamıyla diğerinin tüm tabloları sorgulanır; dönen satır sayısı sıfır değilse derleme kırılır.
Dördüncüsü en değerlisi. Bir kez yazılan bu test, sonraki iki yıl boyunca üç ayrı yanlış yapılandırmayı üretim öncesinde yakaladı.
Karar tablosu
| Ölçüt | Ayrı veritabanı | Ayrı şema | RLS | | --- | --- | --- | --- | | İzolasyon gücü | Yüksek | Orta | Yapılandırmaya bağlı | | Göç maliyeti | Yüksek | Orta | Düşük | | Ölçeklenebilirlik | Düşük | Orta | Yüksek | | Kiracı silme kolaylığı | Yüksek | Yüksek | Orta | | İşletme maliyeti | Yüksek | Orta | Düşük |
Özet
Bu üç yol arasında "doğru" olan yok; sizin kısıtlarınıza uyan var. Karar vermeden önce üç soruyu yanıtlayın:
- Beş yıl sonra kaç kiracı bekliyorsunuz?
- Bir müşteri "verimi tamamen silin" dediğinde ne kadar sürede yapabilmelisiniz?
- Sözleşmelerinizde fiziksel ayrım taahhüdü var mı?
Bu üç yanıt, seçimi genellikle tek bir seçeneğe indirger.
- SaaS
- Çok Kiracılılık
- PostgreSQL
- Güvenlik