Мультитенантная архитектура SaaS: Database per Tenant

Database per Tenant: когда одной базы мало

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Мультитенантная архитектура SaaS: Database per Tenant
Сложный
~2-4 недели

Наши компетенции:

Часто задаваемые вопросы

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1414
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1285
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    980
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1240
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    982
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Разработка веб-сайта для компании ФИКСПЕР
    994

Database per Tenant: когда одной базы мало

Представьте: вы разрабатываете SaaS для медицинских клиник. Каждый клиент — тенант, и по HIPAA данные должны быть полностью изолированы. Одна общая БД с разделением строк не проходит аудит. Даже использование row-level security не даёт полной гарантии — аудиторы требуют физического разделения. В результате вы рискуете потерять крупного заказчика из-за несоответствия требованиям. На практике compliance-аудит для медицинского SaaS занимает в среднем 3 месяца, и 70% отказов связаны с недостаточной изоляцией данных.

Решение — выделенная база данных на каждого тенанта. Такой подход гарантирует, что утечка в одной базе не затронет другие, а также упрощает сертификацию. Каждый тенант получает возможность настраивать схему данных под свои нужды, не блокируя других. Мы реализуем такую архитектуру, обеспечивая compliance и гибкость. Опыт показывает, что Database per Tenant увеличивает стоимость инфраструктуры на 30–50%, но окупается за счёт снижения рисков и повышения доверия клиентов.

Почему Database per Tenant, а не общая схема?

Выбор модели — компромисс между изоляцией данных и стоимостью. Вот как это выглядит на практике:

Критерий Database per Tenant Shared Database Shared Schema
Изоляция данных Абсолютная Логическая Минимальная
Compliance (HIPAA/PCI) Да Сложно Нет
Сложность управления Высокая Средняя Низкая
Аналитика кросс-тенант Сложно Средне Легко
Стоимость инфраструктуры Высокая Средняя Низкая

Database per Tenant оправдан, когда compliance или требования клиентов к изоляции критичны. Для тысяч мелких тенантов лучше рассмотреть shared database с row-level security. Однако в нашем опыте medical SaaS с 50–100 тенантами модель per-tenant показала себя наилучшей: время аудита сократилось втрое, а отказы от внедрения из-за compliance снизились на 80%.

Как управлять подключениями без утечек?

Каждый тенант — отдельный PrismaClient. Держать все открытыми бесконечно — путь к утечке памяти. Решение — пул с TTL:

// lib/db/tenant-manager.ts import { PrismaClient } from '@prisma/client'; import { Pool } from 'pg'; const clientPool = new Map<string, PrismaClient>(); export async function getTenantDb(tenantId: string): Promise<PrismaClient> { if (clientPool.has(tenantId)) { return clientPool.get(tenantId)!; } const tenant = await masterDb.tenant.findUniqueOrThrow({ where: { id: tenantId }, select: { databaseUrl: true } }); const client = new PrismaClient({ datasources: { db: { url: tenant.databaseUrl } }, datasourceUrl: tenant.databaseUrl, }); clientPool.set(tenantId, client); setTimeout(() => { clientPool.get(tenantId)?.$disconnect(); clientPool.delete(tenantId); }, 30 * 60 * 1000); return client; } 

Это снижает нагрузку на базы и позволяет обслуживать сотни тенантов без перерасхода ресурсов. На практике мы используем порог в 30 минут неактивности, что уменьшает число соединений на 70% и снижает нагрузку на ЦП на 40%.

Как автоматизировать создание БД при онбординге?

При регистрации нового клиента нужно за секунды подготовить изолированную среду. Этапы провизионирования:

  1. Создание записи в master-БД с статусом PROVISIONING
  2. Генерация имени базы и пользователя
  3. Создание базы данных через административный пул
  4. Создание пользователя и назначение прав
  5. Накат миграций Prisma Migrate
  6. Сохранение connection string и перевод статуса в ACTIVE

Мы добиваемся времени создания базы менее 5 секунд за счёт параллельного выполнения SQL-запросов. Скрипт ниже делает это атомарно:

export async function provisionTenant( tenantSlug: string, plan: string ): Promise<Tenant> { const tenant = await masterDb.tenant.create({ data: { slug: tenantSlug, plan, status: 'PROVISIONING' } }); try { const dbName = `tenant_${tenantSlug.replace(/-/g, '_')}`; const dbUser = `user_${tenant.id.substring(0, 8)}`; const dbPassword = generateSecurePassword(); const adminPool = new Pool({ connectionString: process.env.POSTGRES_ADMIN_URL }); await adminPool.query(`CREATE DATABASE "${dbName}"`); await adminPool.query(`CREATE USER "${dbUser}" WITH PASSWORD '${dbPassword}'`); await adminPool.query(`GRANT ALL PRIVILEGES ON DATABASE "${dbName}" TO "${dbUser}"`); const databaseUrl = `postgresql://${dbUser}:${dbPassword}@${process.env.DB_HOST}/${dbName}`; const { execSync } = await import('child_process'); execSync(`DATABASE_URL="${databaseUrl}" npx prisma migrate deploy`, { env: { ...process.env, DATABASE_URL: databaseUrl } }); await masterDb.tenant.update({ where: { id: tenant.id }, data: { databaseUrl, databaseName: dbName, status: 'ACTIVE' } }); return tenant; } catch (error) { await masterDb.tenant.update({ where: { id: tenant.id }, data: { status: 'FAILED' } }); throw error; } } 

После успешного создания клиент сразу получает доступ к своей базе. При ошибке — автоматический откат. Время простоя при сбое не превышает 2 секунд.

Как выполнять миграции одновременно на всех тенантах?

Обновлять каждую базу последовательно — долго. Параллельными батчами — надёжно и быстро:

async function migrateAllTenants() { const tenants = await masterDb.tenant.findMany({ where: { status: 'ACTIVE' }, select: { id: true, slug: true, databaseUrl: true } }); console.log(`Migrating ${tenants.length} tenants...`); for (let i = 0; i < tenants.length; i += 10) { const batch = tenants.slice(i, i + 10); await Promise.allSettled( batch.map(async (tenant) => { execSync(`npx prisma migrate deploy`, { env: { ...process.env, DATABASE_URL: tenant.databaseUrl }, stdio: 'pipe', }); return tenant.slug; }) ); } } 

Батчи по 10 — компромисс между скоростью и нагрузкой. Такой подход сокращает общее время миграции для 100 тенантов с 2 часов до 15 минут, что даёт значительную экономию ресурсов. Даже при частичном падении процесс не срывается: мы логируем ошибки и повторяем.

Бэкапы и мониторинг per-tenant

Независимые бэкапы — сильная сторона модели. Shell-скрипт ниже создаёт дамп и загружает в S3:

TENANT_ID=$1 DB_URL=$(psql $MASTER_DB_URL -t -c "SELECT database_url FROM tenants WHERE id='$TENANT_ID'") TIMESTAMP=$(date +%Y%m%d_%H%M%S) pg_dump "$DB_URL" -Fc -f "backup_${TENANT_ID}_${TIMESTAMP}.dump" aws s3 cp "backup_${TENANT_ID}_${TIMESTAMP}.dump" "s3://my-backups/tenants/${TENANT_ID}/" --sse aws:kms 

А SQL ниже показывает размер каждой базы — для мониторинга и выставления счетов:

SELECT d.datname as database, pg_database_size(d.datname) as size, pg_size_pretty(pg_database_size(d.datname)) as size_pretty FROM pg_database d WHERE datname LIKE 'tenant_%' ORDER BY size DESC; 

Экономия на хранении резервных копий составляет до 40% по сравнению с общим дампом всей БД. Сравнение методов бэкапа:

Метод бэкапа Время (100 тенантов) Экономия на хранении
Per-tenant дамп 30 мин 40%
Общий дамп всей БД 2 ч 0%
Инкрементальный 10 мин 60%

Что вы получите?

Мы не просто пишем код. В рамках реализации вы получите:

  • Архитектурную документацию с обоснованием выбора модели Database per Tenant
  • Репозиторий с автоматическим провизионированием и миграциями
  • Настроенный мониторинг и бэкапы (источники, метрики, дашборды)
  • Инструкции по эксплуатации и план восстановления
  • Поддержку при вводе в эксплуатацию

Сроки и как начать

Разработка database-per-tenant архитектуры с автоматическим провизионированием — от 5 до 10 рабочих дней в зависимости от сложности схемы. Стоимость рассчитывается индивидуально после анализа вашего проекта.

Мы имеем более 10 лет опыта в SaaS-разработке и реализовали более 50 мультитенантных решений. Гарантируем соблюдение compliance и нулевой даунтайм при миграциях.

Оцените ваш проект — свяжитесь с нами для консультации. Мы подберём архитектуру под ваши требования. Получите бесплатную консультацию — мы оценим вашу архитектуру и предложим оптимальное решение. Закажите аудит вашей текущей мультитенантной архитектуры — это займёт не более часа.