Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Які існують архітектурні підходи до мультиорендності в Laravel і як обрати?

Мультиорендність (multi-tenancy) - один застосунок обслуговує багато клієнтів-орендарів (компанії, школи, магазини), і дані кожного мають бути ізольовані від інших.

Три основні моделі зберігання:

1. Спільна база, колонка tenant_id:

#[ScopedBy(TenantScope::class)]
class Project extends Model {}

final class TenantScope implements Scope
{
    public function apply(Builder $builder, Model $model): void
    {
        $builder->where('tenant_id', app(CurrentTenant::class)->id);
    }
}
  • плюси: просто, дешево, одна міграція на всіх, легко робити звіти по всіх орендарях;
  • мінуси: ізоляція тримається на коді - один забутий фільтр (сирий запит, withoutGlobalScopes, джоба без контексту орендаря) - і дані одного клієнта бачить інший. «Галасливий сусід» навантажує базу для всіх.

Посилення: Row-Level Security у PostgreSQL - політика на рівні бази (USING (tenant_id = current_setting('app.tenant_id')::int)): навіть помилка в застосунку не поверне чужих рядків. Застосунок встановлює змінну сесії бази на кожен запит.

2. Окрема схема на орендаря (PostgreSQL schemas): ізоляція сильніша, бекап і відновлення окремого клієнта простіші, але міграції треба проганяти по всіх схемах, а тисячі схем ускладнюють обслуговування.

3. Окрема база на орендаря: найсильніша ізоляція, окремі ресурси, можливість розмістити великого клієнта на окремому сервері чи в іншому регіоні (вимоги до зберігання даних). Ціна - складна інфраструктура, міграції по сотнях баз, з'єднання, крос-орендна аналітика.

Що треба вирішити незалежно від моделі:

  • визначення поточного орендаря: піддомен (acme.app.com), домен, шлях, обраний у сесії - і перевірка, що користувач належить орендарю;
  • контекст у фонових процесах: джоби, команди, планувальник не мають запиту - ідентифікатор орендаря передається явно в задачу й відновлюється перед виконанням;
  • кеш, файли, черги, пошук - ключі й шляхи з префіксом орендаря, інакше витік через кеш;
  • унікальність - unique(['tenant_id', 'email']), а не глобальна;
  • тести ізоляції: для кожного ресурсу - «орендар A не бачить даних орендаря B».

Як обрати: більшість SaaS починає зі спільної бази з tenant_id (+ RLS для критичних даних) і переходить до окремих баз лише для великих клієнтів чи регуляторних вимог. Пакети stancl/tenancy і spatie/laravel-multitenancy реалізують обидва підходи.

Докладніше в документації: PostgreSQL: політики безпеки рядків

Схожі питання