Мы часто сталкиваемся с задачей построить SaaS-платформу, где одна инсталляция приложения обслуживает сотни клиентов — каждый со своими данными, но с единым кодом. Неправильная изоляция приводит к утечкам, а избыточная — к непомерным затратам. На одном из проектов с 200 компаниями отсутствие RLS стоило клиенту двух крупных заказчиков — потеря дохода составила $50 000. После внедрения нашего решения инциденты прекратились, а стоимость обслуживания снизилась на 40% — экономия $15 000 в год. Получите консультацию инженера по вашему проекту.
Типичная ситуация: пятьдесят компаний за первый месяц, первая утечка данных ставит проект под угрозу. Чтобы этого избежать, нужен правильный выбор модели и строгая изоляция. Наш опыт на 30+ проектах показывает, что 80% стартапов выбирают Pool-модель благодаря низкому порогу входа и простоте сопровождения. Silo-модель оправдана при 50+ клиентах с высокими требованиями к безопасности (HIPAA, PCI DSS). Гарантируем, что предложенное решение будет соответствовать любым стандартам.
Три модели multi-tenancy: что выбрать?
Всего существует три принципиальных подхода. Они различаются изоляцией, стоимостью и сложностью. Выбор модели — компромисс между безопасностью и скоростью разработки.
| Модель | Изоляция | Сложность | Стоимость | Масштабирование |
|---|---|---|---|---|
| Pool | Средняя | Низкая | Низкая | Высокое |
| Silo | Высокая | Высокая | Высокая | Среднее |
| Bridge | Высокая | Средняя | Средняя | Среднее |
Pool-модель в 5–10 раз дешевле в обслуживании, чем Silo, для 100+ tenant'ов — по нашим оценкам на 30+ проектах. Это снижает операционные расходы на 30–50%. Выбор модели напрямую влияет на TCO: с Pool вы экономите до 50% на инфраструктуре баз данных.
Какую модель выбрать для стартапа?
Для стартапов с небольшим числом клиентов и ограниченным бюджетом оптимальна Pool-модель. Она позволяет быстро запустить продукт и легко масштабироваться до сотен tenant'ов. Если у вас enterprise-клиенты с жёсткими требованиями к изоляции — выбирайте Silo, несмотря на более высокую стоимость обслуживания.Как реализовать Pool-модель с RLS?
Самый распространённый подход для SaaS. Используем Row-Level Security в PostgreSQL, а не только проверки в коде. Это даёт защиту даже при ошибках в ORM. Согласно документации PostgreSQL, эта функция доступна с версии 9.5 (мы рекомендуем 14+ для production). В сочетании с глобальными scope'ами в Laravel получаем надёжную изоляцию.
ALTER TABLE articles ADD COLUMN tenant_id uuid NOT NULL REFERENCES tenants(id);
CREATE INDEX articles_tenant_id_idx ON articles(tenant_id);
ALTER TABLE articles ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON articles
USING (tenant_id = current_setting('app.tenant_id')::uuid);
SET app.tenant_id = '550e8400-e29b-41d4-a716-446655440000';
SELECT * FROM articles; -- только строки этого tenant'а
В Laravel интеграция идёт через глобальный scope и middleware:
class TenantScope implements Scope
{
public function apply(Builder $builder, Model $model): void
{
$builder->where($model->getTable() . '.tenant_id', tenant()->id);
}
}
trait HasTenant
{
protected static function bootHasTenant(): void
{
static::addGlobalScope(new TenantScope());
static::creating(function ($model) {
$model->tenant_id ??= tenant()->id;
});
}
}
class InitializeTenancy
{
public function handle(Request $request, Closure $next)
{
$subdomain = explode('.', $request->getHost())[0];
$tenant = Tenant::where('subdomain', $subdomain)->firstOrFail();
app()->instance('tenant', $tenant);
DB::statement("SET app.tenant_id = '{$tenant->id}'");
return $next($request);
}
}
Идентификация tenant'а по поддомену
Самый удобный способ — поддомен: acme.app.example.com. Роутинг в Laravel:
Route::domain('{tenant}.example.com')->group(function () {
Route::middleware([InitializeTenancy::class])->group(function () {
// все защищённые роуты
});
});
| Метод идентификации | Сложность | SSL-настройка | Пример |
|---|---|---|---|
| Поддомен | Низкая | Wildcard-сертификат (Let's Encrypt) | acme.app.com |
| Кастомный домен | Средняя | Отдельный сертификат на клиента | app.acme.com |
| Path-based | Низкая | Основной домен | app.com/acme |
Идентификация tenant'а по поддомену занимает менее 1 мс благодаря кэшированию в Redis. Это решение поддерживает до 10 000 tenant'ов на одном сервере без деградации скорости.
Почему Silo-модель оправдана для enterprise?
Отметим: когда клиенту нужна полная изоляция данных или compliance (HIPAA, PCI DSS), используем динамическое переключение соединения. Миграции выполняются для каждого tenant'а отдельно через Artisan-команду tenants:migrate. Настройка занимает 1 неделю, зато даёт гарантию, что данные одного клиента никогда не смешаются с другим.
class TenantDatabaseManager
{
public function connectTenant(Tenant $tenant): void
{
$config = [
'driver' => 'pgsql',
'host' => $tenant->db_host ?? config('database.connections.pgsql.host'),
'database' => "tenant_{$tenant->id}",
'username' => $tenant->db_user,
'password' => Crypt::decrypt($tenant->db_password),
];
Config::set("database.connections.tenant", $config);
DB::purge('tenant');
DB::reconnect('tenant');
DB::setDefaultConnection('tenant');
}
}
Как автоматизировать provisioning tenant'а?
Provisioning — ключевой этап, который нельзя делать синхронно. Мы реализуем его через очередь Laravel. Типичный пайплайн:
- Создание записи tenant в таблице
tenants. - Запуск
ProvisionTenantJobв очереди. - Воркер создаёт базу данных (или схему), запускает миграции и сиды.
- Настройка DNS-записей (CNAME/поддомен).
- Отправка welcome-письма клиенту.
Всё это занимает до 30 секунд — пользователь ждёт только создания записи tenant'а.
class ProvisionTenantJob implements ShouldQueue
{
public function handle(Tenant $tenant): void
{
TenantDatabaseManager::create($tenant);
Artisan::call('tenants:migrate', ['--tenant' => $tenant->id]);
Artisan::call('tenants:seed', ['--tenant' => $tenant->id]);
CloudflareDNS::createSubdomain($tenant->subdomain);
Mail::to($tenant->owner_email)->send(new TenantWelcome($tenant));
$tenant->update(['status' => 'active']);
}
}
Настройка wildcard-сертификата с Caddy: Caddy автоматически получает сертификаты от Let's Encrypt, достаточно указать *.example.com в Caddyfile. HTTPS готов за пару минут.
Что такое feature flags per tenant?
Для разграничения фич по клиентам используем отдельную таблицу tenant_features: колонки tenant_id, feature, enabled, config. В приложении проверяем через tenant()->hasFeature('analytics'). Это позволяет включать функции для конкретных клиентов без деплоя, что особенно удобно при A/B-тестировании. Например, вы можете включить premium-аналитику только для клиентов с тарифом "Business".
Что входит в работу
При заказе разработки multi-tenancy вы получаете:
- Архитектурное решение с обоснованием выбора модели под ваш сценарий.
- Реализацию идентификации, изоляции и автоматического provisioning.
- Настройку CI/CD для деплоя миграций на всех tenant'ов.
- Документацию по эксплуатации и сценариям доработок.
- Обучение вашей команды (до 2 часов).
Сроки
- Pool-модель с RLS, TenantScope, subdomain routing, provisioning job: 2–3 недели.
- Silo с dynamic connections, custom domains, wildcard SSL, cross-tenant аналитика для superadmin: 1–2 месяца.
Точную оценку дадим после аудита вашего проекта.
Свяжитесь с нами для бесплатной консультации. Закажите аудит архитектуры — мы проанализируем текущую реализацию и предложим оптимальное решение.







