Содержание
Мультитенантность — это архитектура, в которой одно приложение обслуживает многих клиентов, а их данные изолированы друг от друга. На старте большинству SaaS-продуктов подходит общая база данных с идентификатором клиента в каждой таблице: она дешевле в поддержке, а крупных клиентов с особыми требованиями позже можно вынести в отдельные базы.
Разберём три модели мультитенантности, их плюсы и минусы, способы защиты от утечки данных и как выбрать модель для своего продукта.
Какие бывают модели мультитенантности?
Есть три основные модели: все клиенты в общих таблицах, у каждого клиента своя схема в общей базе или у каждого своя база данных. Чем сильнее изоляция, тем выше стоимость инфраструктуры и сложнее обновления.
| Модель | Изоляция | Стоимость | Обновления схемы | Когда выбирать |
|---|---|---|---|---|
| Общие таблицы с tenant_id | Логическая | Низкая | Одна миграция | Большинство SaaS на старте |
| Схема на клиента | Средняя | Средняя | Миграция для каждой схемы | Десятки–сотни клиентов, B2B |
| База на клиента | Полная | Высокая | Миграция для каждой базы | Требования регуляторов, крупные контракты |
Как устроить общую базу безопасно?
В общей базе каждая таблица с клиентскими данными содержит идентификатор клиента, а фильтр по нему применяется автоматически, а не вручную в каждом запросе. Забытый фильтр — самый частый источник утечки данных между клиентами.
// Глобальный скоуп: все запросы модели фильтруются по текущему клиенту
class TenantScope implements Scope
{
public function apply(Builder $builder, Model $model): void
{
$builder->where($model->getTable() . '.tenant_id', Tenant::current()->id);
}
}
Дополнительные уровни защиты:
- политики безопасности на уровне строк в PostgreSQL как вторая линия обороны;
- идентификатор клиента в составных индексах и уникальных ограничениях;
- автотесты, которые проверяют, что клиент А не видит данные клиента Б;
- отдельные префиксы для кеша, файлов и очередей каждого клиента.
Про типичные уязвимости веб-приложений — в статье OWASP Top 10 простыми словами.
Фото: Unsplash
Когда нужна отдельная база для клиента?
Отдельная база нужна, когда клиент требует физической изоляции данных по договору или закону, когда данные нужно хранить в определённой стране или когда один клиент создаёт нагрузку, сопоставимую со всеми остальными вместе. Обычно это корпоративный тариф с отдельной ценой.
Цена изоляции:
- Миграции нужно прогонять по всем базам и следить, чтобы ни одна не отстала.
- Отчёты по всем клиентам собираются из многих источников.
- Резервные копии, мониторинг и подключения множатся с каждым клиентом.
- Новому клиенту нужно создать базу — это автоматизируют при регистрации.
Что выбрать на старте?
На старте выбирайте общую базу с идентификатором клиента во всех таблицах и автоматической фильтрацией. Это даёт быстрый запуск и дешёвую поддержку, а при правильной подготовке позволяет позже вынести отдельных клиентов в изолированные базы.
Что заложить сразу:
- идентификатор клиента во всех таблицах с клиентскими данными, даже если сейчас кажется лишним;
- определение текущего клиента в одном месте — по поддомену, домену или токену;
- лимиты по тарифу, чтобы один клиент не забрал все ресурсы;
- выгрузку данных клиента — она понадобится и для переноса, и по требованию закона.
О том, как связать архитектуру с тарифами, мы писали в статьях модель монетизации SaaS и юнит-экономика SaaS.
Как не допустить проблем с «шумными соседями»?
«Шумный сосед» — клиент, который своей нагрузкой замедляет остальных. Защищаются от этого лимитами и разделением ресурсов: тяжёлые операции идут через очереди с квотами на клиента, а API ограничивает частоту запросов.
- ограничение частоты запросов к API по клиенту и тарифу;
- отдельные очереди или приоритеты для импорта, экспорта и отчётов;
- мониторинг нагрузки в разрезе клиентов, чтобы видеть, кто её создаёт;
- переселение крупных клиентов на выделенные ресурсы без изменения кода.
Коротко
- Мультитенантность — одно приложение для многих клиентов с изоляцией данных.
- Модели: общие таблицы, схема на клиента, база на клиента — изоляция растёт вместе со стоимостью.
- На старте подходит общая база с tenant_id и автоматическим фильтром.
- Утечки предотвращают глобальные фильтры, политики на уровне строк и автотесты.
- Крупных клиентов и требования регуляторов решают выделенными базами позже.
Частые вопросы
Можно ли перейти с общей базы на отдельные позже?
Можно, если с самого начала у каждой записи есть идентификатор клиента. Тогда данные одного клиента легко выгрузить и перенести в отдельную базу, не переписывая приложение.
Как давать клиентам свои домены?
Приложение определяет клиента по домену или поддомену запроса, а сертификаты выпускаются автоматически. Это не зависит от модели хранения данных и добавляется на любом этапе.
Что делать, если один клиент нагружает систему больше остальных?
Ввести лимиты по тарифу, вынести тяжёлые операции в очереди с квотами и при необходимости переселить крупного клиента на выделенные ресурсы.



