İçeriğe geç
wedevit

17 Ağustos 2026 · 10 dk okuma · yazılım

İlhan Buğra Aslan

Her müşteriye ayrı kurulum mu, tek uygulama mı? Çok kiracılı (multi-tenant) SaaS mimarisi ve veri izolasyonu


Yeni bir müşteri geldiğinde ekipte hep aynı soru tartışılıyor: ayrı bir kurulum mu açalım, müşteriyi mevcut uygulamaya mı alalım? Kısa cevap müşteri sayısı ve izolasyon beklentisiyle belirlenir. Az sayıda müşteriniz varsa ve her biri verisinin ayrı bir yerde durmasını şart koşuyorsa müşteri başına ayrı kurulum makul. Yüzlerce müşteriye ölçeklenecekseniz paylaşımlı altyapı tek sürdürülebilir yol, çünkü Microsoft'un çok kiracılı mimari kılavuzunun ifadesiyle tek kiracı belirli bir altyapı maliyeti gerektiriyorsa 100 kiracı büyük olasılıkla bunun 100 katını gerektirir. Olgun ürünlerin çoğu ikisinin ortasında bir yerde duruyor: varsayılan paylaşımlı, isteyen ve bunun için ödeyen müşteri için ayrılmış. Zor olan kısım seçim yapmak değil. Aynı kılavuzun uyardığı gibi sonradan başka bir modele geçmek bazen maliyetli olur, o yüzden bu karar ilk müşteriden önce verilmeli.

Üç model: silo, havuz ve ikisinin karışımı

Sektörde yerleşmiş adlandırma AWS'in SaaS kiracı izolasyonu dokümanından geliyor. Silo modelinde her kiracı kendi bağımsız yığınında çalışır, veri tamamen ayrıdır. Havuz (pool) modelinde kiracılar altyapının bir kısmını ya da tamamını paylaşır; verimlilik ve maliyet avantajı buradadır, izolasyon ise artık ağ ve kimlik sınırlarıyla değil sizin tasarımınızla sağlanır. Köprü (bridge) modeli ikisinin karışımıdır: örneğin web katmanı tüm kiracılar tarafından paylaşılır, iş mantığı ve veri katmanı kiracı başına ayrılır.

Bu üçlüyü keskin bir seçim gibi düşünmemek gerekiyor. Microsoft'un mimari kılavuzu izolasyonu bir yelpaze olarak tanımlıyor: hiçbir şeyin paylaşılmadığı uçtan her şeyin paylaşıldığı uca kadar, ve her katman için farklı bir nokta seçebilirsiniz. Pratikte en sık işe yarayan bileşim şu: tek alan adı, tek uygulama katmanı, kiracı başına ayrı veritabanı. Kılavuzun yatay bölümleme dediği bu desen özellikle gürültülü komşu problemini hedef alır, çünkü yükün büyük kısmını taşıyan bileşen genelde veritabanıdır.

Karar teknik olmaktan çok ticari

Modeli belirleyen sorular mimari diyagramında görünmüyor. Üç yıl sonra kaç müşteriniz olacak? Müşterileriniz her tür paylaşımı kabul eder mi, yoksa sözleşme görüşmesinde "verimiz başka firmaların verisiyle aynı veritabanında durmasın" cümlesi çıkıyor mu? Operasyon ekibiniz kaç kişi ve altyapı yönetiminin ne kadarını otomatikleştirebiliyorsunuz? Müşteriye taahhüt ettiğiniz erişilebilirlik seviyesi var mı?

Son soru silo modelinde en çok hafife alınan yer. Kiracı başına ayrı kurulum, sağlama (provisioning) işi baştan sona kodla yapılmadığı sürece her yeni müşteriyi küçük bir projeye çevirir. Yeni sürüm çıktığında güncelleme işi kiracı sayısıyla çarpılır. Bu maliyet ilk beş müşteride görünmez, yirmincide ekibin yarısını yutar. Silo modelini seçiyorsanız altyapıyı kod olarak tanımlamak tercih değil, ön koşuldur.

Veri katmanında dört seçenek ve ölçek sınırları

Azure SQL Database'in çok kiracılı desen karşılaştırması bu dört seçeneği net biçimde ayırıyor. Birincisi tamamen bağımsız uygulama ve veritabanı: en güçlü izolasyon, en yüksek maliyet, çünkü her veritabanı kendi tepe yüküne göre boyutlanır ve ölçek yüzler mertebesinde kalır. İkincisi paylaşımlı uygulama ve kiracı başına veritabanı: izolasyon yine güçlü, kaynak havuzlarıyla maliyet makul seviyeye iner ve tek bir kiracı için şema özelleştirmesi mümkün olur; bu desen yüz bin veritabanı ölçeğine kadar yönetilebiliyor. Üçüncüsü tek paylaşımlı veritabanı: kiracı başına maliyet en düşük, izolasyon en zayıf. Dördüncüsü parçalanmış (sharded) çok kiracılı model: her parça birden fazla kiracı tutar, kiracının tüm verisi tek parçada durur ve ölçek pratikte sınırsızdır.

Dördüncü seçeneğin bedeli operasyonda çıkıyor. Hangi kiracının hangi parçada olduğunu tutan bir katalog gerekir, parça ekleme, bölme, birleştirme ve kiracıyı taşıma yordamları yazılmalıdır. Bir de şema kısıtı vardır: kiracı kimliği parçalanan tabloların birincil anahtarının ilk elemanı olmak zorundadır, yoksa taşıma araçları kiracının verisini bulup taşıyamaz. İkinci seçeneğin gizli maliyeti ise sayının kendisinde: bin kiracıyı 20 indeksli tek veritabanında tutuyorsanız bin ayrı veritabanına geçtiğinizde yönetmeniz gereken indeks sayısı 20 bine çıkar. Bu ölçekte indeks bakımını elle yapmak mümkün değildir, otomatik araçlara devretmeniz gerekir.

Şema başına kiracı: ortadaki yol, gecikmeli faturası

PostgreSQL kullanan ekiplerin sık seçtiği beşinci bir yol var: tek veritabanı, kiracı başına ayrı şema. Cazip görünüyor, çünkü tek bağlantı havuzu yeterli, ayrım gözle görülür ve tek bir kiracının verisini almak kolay. Faturası ilerideki göç işlemlerinde kesiliyor.

Sorun şema sayısının kendisi değil, her şey defalarca yapıldığı içindir. Tek başına iki saniye süren bir göç, 800 kiracıda yarım saate yakın bir yayın adımına dönüşür ve ortada başarısız olduğunda elinizde iki farklı şema sürümü çalıştıran bir sistem kalır. Sistem katalogu kiracı sayısı ile tablo sayısının çarpımı kadar büyür, planlayıcı her sorguda o kataloğa bakar. Kiracılar arası tek bir rapor almak istediğinizde N şemayı birleştiren sorgular yazmak zorunda kalırsınız. Birkaç yüz kiracıya kadar, göçleri sırayla çalıştırıp kaldığı yerden devam edebilen bir orkestrasyonunuz varsa bu model yaşar. Hedefiniz binlerse baştan kiracı başına veritabanına ya da kiracı kimliğiyle paylaşılan tablolara karar vermek daha ucuza gelir.

Row level security açık görünüyor, çalışmıyor olabilir

Paylaşılan tablolarda izolasyonu veritabanına yaptırmanın yolu PostgreSQL'de satır seviyesi güvenlik (RLS). Doğru kurulduğunda çok iyi çalışır. Üç sessiz tuzağı var ve üçü de belgelerde açıkça yazıyor.

Birincisi sahiplik. RLS bir tabloda etkinleştirildiğinde politika yoksa varsayılan olarak hiçbir satır görünmez, bu iyi haber. Kötü haber şu: süper kullanıcılar, BYPASSRLS yetkisine sahip roller ve tablonun sahibi politikaları varsayılan olarak atlar. Uygulamalar göçleri çalıştıran rolle bağlandığı için genelde tablonun sahibidir, yani politikalar yazılmıştır ama hiçbir zaman devreye girmez. Çözüm ya tabloya FORCE ROW LEVEL SECURITY uygulamak ya da uygulamayı hiçbir şeyin sahibi olmayan ayrı bir rolle bağlamaktır.

İkincisi bütünlük kontrolleri. Tekillik, birincil anahtar ve yabancı anahtar kontrolleri veri bütünlüğünü korumak için RLS'i her zaman atlar. PostgreSQL belgeleri bunun bir örtük kanal (covert channel) oluşturabileceğini söylüyor: tablo genelinde tekil olan bir e-posta alanına kayıt denediğinizde dönen "duplicate key" hatası, o değerin başka bir kiracıda kullanıldığını söyler. Tekillik kısıtlarını (kiraci_id, eposta) gibi kiracı kapsamlı tanımlamak bu sızıntıyı kapatır.

Üçüncüsü bağlantı havuzlaması. Yaygın kalıp, kiracı kimliğini bir oturum değişkenine yazıp politikanın current_setting ile okumasıdır. PgBouncer'ı işlem (transaction) havuzlama modunda kullanıyorsanız SET ve RESET bu modda desteklenmez; değeri işlemin dışında yazdığınızda sunucu bağlantısı başka bir kiracıya devredilirken ayar üzerinde kalabilir. Kiracı bağlamı sorguyu çalıştıran işlemin içinde SET LOCAL ile verilmeli. Politikaların birleşme kuralını da bilin: izin veren (permissive) politikalar OR ile, kısıtlayıcı (restrictive) politikalar AND ile birleşir. "Yöneticiler her şeyi görsün" diye eklenen ikinci bir izin veren politika, kiracı sınırını daraltmaz, genişletir.

İzolasyon ile yetkilendirme aynı şey değil

Bu ayrım kaçırıldığında ortaya çıkan hata sınıfı, OWASP API Güvenliği Top 10 listesinde 2019'da birinci sıradaydı, 2023 sürümünde de birinci sırada kaldı: nesne seviyesinde bozuk yetkilendirme (BOLA). Rol tabanlı yetkilendirme kullanıcının hangi işlemi yapabileceğini söyler. İzolasyon ise kimin verisine dokunabileceğini söyler. Biri "bu kullanıcı fatura görebilir" der, diğeri "ama yalnızca kendi şirketinin faturalarını" der. İkinci kontrolü tek bir uç noktada atlamak yeterlidir.

Buradan çıkan kural basit: kiracı kimliği her zaman kimlik doğrulama sonucundan, yani token'dan türetilir. URL'den, sorgu parametresinden, başlıktan ya da istek gövdesinden gelen kiracı kimliğine güvenilmez. AWS'in SaaS kılavuzu bir adım daha ileri gidiyor: kiracı bağlamı JWT'den okunduktan sonra izolasyon uygulama kodunun bir katman altında, kiracıya daraltılmış geçici kimlik bilgileriyle uygulanmalı ve bu iş sarmalayıcılara alınarak her geliştiricinin aklında tutması gereken bir ayrıntı olmaktan çıkarılmalı. PostgreSQL tarafındaki karşılığı, RLS ile birlikte kiracı kapsamı verilmeden sorgu üretmeyi reddeden bir veri erişim katmanıdır.

Testi de yazılı hale getirin. Yöntem OWASP'ın önerdiği kadar basit: iki farklı kiracıda hesap açın, A'nın token'ıyla B'nin kayıt kimliklerini isteyin, cevabın 403 ya da 404 olmasını bekleyin. Bunu tek seferlik bir denetim değil, test otomasyonu kapsamında hatta çalışan bir gerileme testi yapın. Uç nokta bazlı örnekleri API güvenliği ve OWASP API Top 10 yazımızda ayrıntılandırdık.

Gürültülü komşu ve patlama yarıçapı

Paylaşılan veritabanının en somut riski, tek bir kiracının ağır raporunun herkesin yanıt süresini bozması. Bulut sağlayıcılarının belgeleri burada açık konuşuyor: paylaşılan bir veritabanında bireysel kiracının kaynak tüketimini izleyecek hazır bir mekanizma yok, ölçümü uygulama katmanında siz kurmak zorundasınız. En az üç sayıyı kiracı kırılımında tutun: istek başına sorgu süresi, taranan satır sayısı ve depolama.

Sonrasında müdahale araçları elinizde olur: kiracı bazlı hız sınırı, ağır işleri ayrı kuyruğa alma, raporlamayı okuma kopyasına taşıma ve en ağır kiracıyı kendi veritabanına çıkarma. İkinci risk dağıtım tarafında. Havuz modelinde bozuk bir sürüm ya da yanlış bir göç tüm müşterileri aynı anda etkiler; silo ya da damga (stamp) modelinde aynı değişikliği kiracı kiracı ilerletebilirsiniz. Kademeli yayın ve geri dönüş adımlarını küçük ekipler için CI/CD yazımızda, eşik ve uyarı kurmayı izlenebilirlik, SLO ve hata bütçesi yazımızda ele aldık.

Tek bir müşteriyi dünkü hâline döndürebiliyor musunuz?

Bu soru mimari tartışmasını çoğu zaman tek başına bitirir. Kiracı başına veritabanında cevap kolaydır: o veritabanını zaman noktasına geri alırsınız, diğer müşteriler etkilenmez. Kiracıların aynı tabloları paylaştığı modelde ise veritabanını geri almak herkesi geri alır. İşin doğrusu, kiracı kapsamlı bir dışa aktarma ve geri yazma yolunu bilerek inşa etmek ve bunu tatbikat etmektir.

Aynı mekanizma dört ayrı ihtiyaca hizmet eder: sözleşme bitiminde müşterinin verisini eksiksiz teslim etmek, silme ve aktarma taleplerini karşılamak (bunların bir kısmı mevzuata bağlı süreler taşır), bir kiracıyı paylaşımlı veritabanından kendi veritabanına taşımak ve gerçek bir kiracının kopyasını test ortamına almak. Bu yollar yoksa hiçbiri yok demektir ve dördü de ilk ihtiyaç duyulduğunda baskı altında yazılır. Yedeğin varlığı ile geri dönebilme arasındaki farkı 3-2-1 yedekleme kuralı yazımızda, verinin ve kodun kime ait olduğunu kaynak kod mülkiyeti ve emanet yazımızda anlattık.

Kiracı başına maliyeti ölçmüyorsanız fiyatınızı bilmiyorsunuz

Silo modelinde bir müşterinin maliyeti faturada okunur. Havuz modelinde okunmaz ve AWS bunu paylaşımlı modelin bilinen dezavantajları arasında sayıyor: tüketimi tek tek kiracılara atfetmek için sistemi kendiniz enstrümante etmeniz gerekir. Bu ölçüm olmadan fiyat kademelerini tahminle kurarsınız ve kârı yiyen müşteriyi göremezsiniz.

Başlangıç için ağır bir maliyet analizi platformu gerekmiyor. Her istek kaydına kiracı kimliğini yazın, kiracı başına depolama ve toplam sorgu süresini haftalık toplayın, ayda bir ilk on kiracıyı listeleyin. Bu liste iki karar üretir: hangi müşterinin kendi veritabanına çıkması gerektiği ve fiyat kademelerinin nerede kesileceği. Yan faydası da var, "bize özel sunucu ister" talebi tartışma konusu olmaktan çıkıp fiyatlı bir seçeneğe dönüşür.

Bugün tek müşteriniz olsa bile şemaya kiracı kimliği koyun

En düşük maliyetli sigorta bu. Azure'un melez model önerisi tam olarak buna dayanıyor: tüm veritabanları şemasında kiracı kimliğini taşır, bazıları pratikte tek kiracı barındırır. Kiracı sayısının şemaya etkisi olmadığı için bir müşteriyi paylaşımlı veritabanından kendi veritabanına, gerektiğinde geri taşımak sıradan bir operasyona dönüşür. Deneme sürümündeki kiracılar paylaşımlı yerde durur, üst kademeye geçen müşteri kendi veritabanına çıkar.

Buna iki şey eşlik etmeli. Birincisi kiracıyı hangi kurulumun barındırdığını tutan bir eşleme tablosu; bu kayıt olmadan isteği doğru yere yönlendiremezsiniz ve kesinti duyurusunu kime yapacağınızı bilemezsiniz. İkincisi kod tabanının iki modu birlikte desteklemesi, çünkü karma modelin asıl riski budur. Dört yıl sonra çalışan bir şemaya kiracı kimliği eklemek, altyapıyı değiştirmekten çok daha pahalıdır; kolonu bugün koymak neredeyse bedavadır.

Bu hafta yapılabilecek beş iş

Bir: kiracı tanımını yazılı hale getirin. Müşteri firma mı kiracı, firmanın departmanı mı, yoksa aynı müşterinin test ve canlı ortamı iki ayrı kiracı mı? Bu tanım netleşmeden geri kalan her karar tahmindir. İki: RLS kullanıyorsanız uygulamanın bağlandığı rolle bir deneme yapın, başka kiracının satırını çekmeye çalışın; satır dönüyorsa muhtemelen tablo sahibiyle bağlanıyorsunuz. Üç: iki kiracı ve takas edilmiş kimliklerle çapraz erişim testi yazın, hattın içine koyun. Dört: "X müşterisini dün saat 14.00'e döndür" tatbikatını yapın ve süreyi ölçün. Beş: istek kayıtlarına kiracı kimliğini ekleyip kiracıları sorgu süresine ve depolamaya göre sıralayın.

Bu beş adımın çıktısı, hangi modele geçmeniz gerektiğini tartışmadan önce mevcut modelin neyi garanti ettiğini gösterir. Kanıtlayamadığınız izolasyon, mimari seçiminden daha acil bir sorundur. Kararın kendisine geldiğinizde ölçüt listesiyle başlamak diyagramla başlamaktan daha hızlı sonuç verir; benzer bir karar çerçevesini monolit mi, mikroservis mi yazımızda da kurmuştuk.


Bu konuda yardıma mı ihtiyacınız var?

iletişime geçtüm yazılar