שלוש רמות בידוד
L1: DB משותף + עמודת tenant_id
זול, מהיר להתחיל. כל הטבלאות עם TenantId. EF Core 10 query filter מוסיף WHERE tenant_id = X אוטומטית. מתאים ל-startup וכן ל-B2B עם tenants הומוגניים. סכנה: filter שכוח אחד - דליפה. חוזה ITenantScoped + autotests חובה.
L2: סכמה (search_path) נפרדת לכל tenant
כל tenant - סכמת Postgres משלו. Connection string משותף, אבל middleware מגדיר search_path לפי tenant ב-JWT. בידוד ברמת DDL - אי אפשר לקרוא נתונים זרים בטעות. מתאים לרגולטוריקה. המחיר: migrations × N, monitoring קשה יותר, backup per tenant.
L3: cluster נפרד לכל tenant
כל enterprise tenant - namespace נפרד ב-Kubernetes, DB משלו. בידוד מלא, dedicated SLA, אפשר ב-region של data residency. יקר - רק לתוכניות enterprise.
טריגרי מעבר L1 - L2 - L3
- L1 - L2: enterprise tenant ראשון עם דרישות compliance (HIPAA, GDPR-strict).
- L1 - L2: tenant אחד שובר את הבסיס - noisy neighbor.
- L2 - L3: enterprise דורש data residency במדינה ספציפית או dedicated SLA.
חוזה ITenantScoped
כל ישות חייבת implement ITenantScoped { TenantId }. EF Core query filter גלובלי. Autotest - בודק שישות חדשה בלי TenantId לא קומפלת. בלי החוזה הזה L1 - חבית אבק.
איפה .NET 10 עוזר
- AsyncLocal משופר - TenantContext דרך DI scope + AsyncLocal כבר לא hot path.
- EF Core 10 query filters עם plan cache - בעבר filter per-tenant ביטל את התוכנית; עכשיו לא.
- Native AOT (היכן שאפשר) למיקרו-שירותים - מוריד עלות tenant ב-L1 בערך 30%.
מה לקחת מכאן
- רוב SaaS-B2B צריך להתחיל ברמה 1. אל תסבכו.
- משמעת ITenantScoped + autotests - חוזה בלתי ניתן להפרה.
- הניחו מסלול מעבר L1 - L2 מהחודש הראשון.
- רמה 3 - רק במחיר enterprise. לעולם אל תיתנו "cluster נפרד" כבונוס שיווקי.
קריאה נוספת
מה לקרוא הלאה