Масштабировать SaaS и B2B-продукт нужно по порядку: сначала измерить, где медленно, затем исправить запросы и индексы в базе, вынести тяжёлую работу в фон, добавить кэш с учётом организации, поставить лимиты для клиентов и только после этого думать о репликах, разделении данных и микросервисах. Каждая следующая ступень дороже предыдущей и нужна реже.

Порядок важен, потому что симптом «всё тормозит» одинаков у разных причин. Добавление серверов лечит нехватку мощности, но не лечит запрос без индекса: он будет так же тормозить на десяти серверах, только дороже. Здесь разбор для продукта, у которого клиентов уже заметно больше, чем в первый месяц. Услуга описана на странице «Масштабирование SaaS-продукта», схемы разделения данных клиентов — в статье «Мультиарендность в SaaS».

Коротко. Порядок такой: измерить, исправить запросы и индексы, вынести тяжёлое в фон, кэшировать с ключом организации, ограничить шумных клиентов, добавить реплики чтения, и лишь затем разносить клиентов по группам серверов. Микросервисы масштабируют команду, а не запросы, и нужны реже, чем кажется.

Сначала измерьте: что смотреть и на что реагировать

Масштабирование без измерений превращается в догадки. Достаточно небольшого набора показателей, но снятого по организациям, а не только в целом по системе: проблема часто сидит у одного клиента, а среднее по всем её скрывает.

ПоказательНа что указываетПервое действие
Время ответа по адресам запросов, хвост распределенияКакие экраны и вызовы тормозят у худших клиентов, а не в среднемВзять три самых медленных и разобрать каждый
Медленные запросы в базе данныхНет индекса, лишняя выборка, запрос в циклеПосмотреть план выполнения на данных, близких по объёму к самому крупному клиенту
Длина очередей и время ожидания задачФоновых исполнителей мало или одна задача занимает всехРазделить очереди и поставить ограничения на организацию
Нагрузка по организациямКто создаёт большую часть запросов и хранит больше всего данныхВвести квоты и поговорить с крупными клиентами о режиме работы
Занятость соединений с базойПриложение ждёт базу, а не работаетПул соединений, уменьшение длительных транзакций
Рост хранилища и таблицКакие таблицы растут быстрее остальныхСрок хранения, архив, разделение по времени

Перед изменениями фиксируется базовая картина: те же показатели через неделю после правки должны показать, помогло ли. Без этого непонятно, что именно дало эффект, и не получится остановиться, когда его достаточно.

Первое узкое место: база данных

Обычно первой упирается база, и обычно причина в запросах, а не в железе. Типичные находки при разборе запросов:

  • Нет индекса под реальный запрос. В multi-tenant продукте индекс должен начинаться с идентификатора организации: запросы всегда ограничены организацией, и индекс без неё не помогает.
  • Запрос в цикле. Для списка из пятидесяти записей приложение делает пятьдесят запросов вместо одного. Выглядит безобидно, пока у клиента не появится большой список.
  • Выборка без постраничного вывода. Экран загружает все записи и режет их в браузере.
  • Длинные транзакции. Отчёт держит блокировки, и обычные операции других клиентов ждут.
  • Отчёты на рабочей базе. Тяжёлая аналитика считается на той же базе, что и ежедневная работа.

Лечится это правкой запросов, индексов и пагинацией, без смены архитектуры. Только если после этого база по-прежнему упирается в чтение или запись, переходят к следующим ступеням. Ограничение времени запроса и наблюдение за медленными запросами остаются в продукте навсегда.

Второе: тяжёлую работу — из запроса в фон

Всё, что занимает заметное время, не должно выполняться, пока пользователь ждёт ответа: формирование отчётов, массовые импорты, рассылки, генерация документов, обмен с учётной системой клиента. Такие задачи уходят в очередь, а пользователь получает статус «принято» и уведомление о готовности.

Три правила делают фон надёжным. Задача идемпотентна: повторный запуск после сбоя не создаёт дубль. Очереди разделены по типам: массовый импорт не должен блокировать письма. И есть ограничение на организацию: один клиент может одновременно держать ограниченное число тяжёлых задач, остальные ждут своей очереди. Без третьего правила один клиент с большим файлом занимает всех исполнителей, и это та самая проблема «шумного соседа».

Третье: кэш, который не смешивает клиентов

Кэш снимает нагрузку с базы, но в multi-tenant продукте это самое опасное место для утечек данных. Ключ кэша обязан включать организацию (а при необходимости и роль): иначе ответ, сохранённый для одного клиента, вернётся другому. Эта ошибка не видна на тестах с одним клиентом, поэтому проверяется парой организаций.

Что кэшируемКлючКогда сбрасываемЧто проверяем
Справочники и настройки организацииОрганизация и версия настроекПри изменении настроекОрганизация A не получает настройки организации B
Результаты тяжёлых расчётовОрганизация, параметры, периодПо расписанию или по событиюУстаревший результат не выдаётся как свежий без метки
Права пользователяПользователь и организацияПри смене роли и при выходеУволенный теряет доступ без задержки
Публичные данные продуктаОбщий ключПри публикацииВ общий кэш не попадают данные клиентов

Кэш не заменяет исправление запроса: он прячет медленный запрос до первого сброса. Сначала правят запрос, потом кэшируют то, что и после правки остаётся дорогим.

Четвёртое: ограничения для клиентов и «шумный сосед»

В B2B-продукте ресурсы общие, а клиенты разные по размеру. Без ограничений один клиент может замедлить всех. Ограничения вводят до первого инцидента, а не после, потому что рассказывать крупному клиенту об ограничении, которое только что появилось, сложнее, чем сообщить о нём в условиях тарифа.

РесурсЧто ограничиваемЧто видит клиент
Запросы к APIЧисло запросов по ключу и организации за промежуток времениПонятный ответ «слишком часто» с указанием, когда повторить
Тяжёлые задачиЧисло одновременных задач на организацию, приоритет в очередиСтатус «в очереди» и оценка ожидания
ХранилищеКвота по тарифуУведомление до достижения предела, а не после
Размер выгрузки и импортаМаксимальный размер файла и число строк за один разПодсказка, как разбить загрузку на части
Число пользователей и объектовЛимиты тарифаПредложение сменить тариф

Ограничения связаны с тарифами и со счётом: так лимит становится частью продукта, а не ограничением, которое инженеры придумали «сверху». Тарифы и счета в B2B SaaS показаны в разборе типовой задачи «Тарифы, подписки и счета в B2B SaaS».

Пятое: реплики чтения и отдельное хранилище для отчётов

Когда запросы исправлены, тяжёлое ушло в фон, а база по-прежнему упирается в чтение, помогает копия базы только для чтения: отчёты и поиск идут на неё, а запись остаётся на основной. У такого решения есть цена, о которой говорят заранее: копия отстаёт от основной. Для отчётов за прошлый месяц это неважно, а экран «мои заказы», который сразу после создания заказа его не показывает, пользователи принимают за сбой.

  • Что можно читать с реплики: отчёты, справочники, поиск, выгрузки.
  • Что читаем с основной базы: всё, что пользователь только что изменил, и всё, что влияет на деньги и права.
  • Аналитика отдельно: когда отчёты вырастают в самостоятельную функцию, их данные копируют в хранилище, рассчитанное на аналитику; продуктовая база перестаёт зависеть от чужих отчётов.
  • Старые данные: разделение таблиц по времени и архив избавляют основную базу от записей, к которым почти не обращаются.

Шестое: когда разносить клиентов по группам серверов

Дальше приходит шаг, который нельзя делать раньше времени: клиентов делят на группы, и у каждой группы свои серверы или своя база. Признаки того, что пора: нагрузка основной базы упирается в запись, один-два клиента по объёму сопоставимы со всеми остальными вместе, или требования крупных клиентов (место хранения, отдельные копии, окно обновлений) несовместимы с общими.

ВариантКогда подходитЧто дорого
Все клиенты на общей базеНагрузка растёт равномерно, особых клиентов нетНичего, пока хватает
Крупные клиенты в отдельной схеме или базеОдин-два клиента ведут себя иначе, чем остальныеОбновления и мониторинг по каждому, реестр клиентов
Клиенты по группам («ячейкам»), в каждой своя база и приложениеОсновная база упёрлась в запись, клиентов многоМаршрутизация запросов, перенос клиента между группами, общие справочники

Разнесение по группам сложно откатить, поэтому к нему идут с замерами, а не по общему впечатлению. Если схема данных с самого начала разделена по организациям и в каждой таблице есть идентификатор клиента, перенос клиента между группами возможен без переписывания. Если идентификатора нет, сначала его добавляют, и это самая большая часть работы.

А микросервисы?

Микросервисы масштабируют команду разработки и независимые релизы, а не отдельные запросы. Запрос без индекса не станет быстрее оттого, что живёт в отдельном сервисе, зато добавится сеть, согласование версий и распределённые транзакции. Выделение сервиса оправдано, когда у части продукта другой ритм изменений, другие требования к нагрузке или отдельная команда. Для всех остальных случаев хватает аккуратно разделённого монолита, как в статье «Микросервисы или монолит». Если продукт действительно упирается в нагрузку и независимые релизы, посмотрите страницу про микросервисную архитектуру и высокую нагрузку.

Масштабируется не только код. Подключение клиентов, обращения в поддержку и релизы тоже упираются в потолок: если каждое подключение занимает полдня у одного сотрудника, продукт растёт со скоростью этого сотрудника. Автоматизировать подключение, дать клиенту самообслуживание и разделить окна обновлений часто выгоднее, чем ещё одна ступень в инфраструктуре.

Что делаем мы и с чего начать

Начинаем с обследования: 200 000 ₽ и 2–3 недели за разбор одного продукта и его базы, 350 000 ₽ и 3–4 недели, если задействовано несколько систем. На выходе карта узких мест по измерениям, порядок снятия с оценкой по каждой ступени и вилка бюджета. Стоимость вычитается из первого этапа, если продолжаете с нами, документом можно пользоваться без нас. Оценку кода и архитектуры отдельно описывает страница «Аудит кода и архитектуры».

Дальше, если нужно, пилот на одном узком месте (150 000–400 000 ₽, 2–8 недель) или вывод в эксплуатацию от 1 500 000 ₽ этапами по 300 000–700 000 ₽, сопровождение от 20 000 ₽ в месяц. Остановиться можно после любой ступени. Мы работаем с одним продуктом, а не с инфраструктурой компании целиком, не дежурим круглосуточно, не проводим нагрузочных атак на боевую систему и не защищаем от DDoS. Исходники лежат в вашем репозитории с первого коммита. Цены — на странице «Тарифы», услуга — на странице «Масштабирование SaaS-продукта».

Частые вопросы

С чего начинать масштабирование SaaS?

С измерений по организациям: время ответа по адресам, медленные запросы в базе, длина очередей, нагрузка клиентов. Затем исправляют запросы и индексы, выносят тяжёлое в фон, добавляют кэш и лимиты. Серверы и сложную архитектуру добавляют в последнюю очередь.

Когда нужны микросервисы?

Когда части продукта нужны независимые релизы, другая нагрузка или отдельная команда. Для производительности запросов они сами по себе не нужны. Часто хватает аккуратно разделённого монолита.

Что такое «шумный сосед» и как его остановить?

Это клиент, чья нагрузка замедляет остальных: тяжёлый отчёт, массовый импорт, скрипт, который обращается к API в цикле. Останавливают его лимитами по организации, отдельными очередями для тяжёлых задач и квотами по тарифу.

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

Когда общая база упирается в запись, когда один-два клиента по нагрузке сопоставимы со всеми остальными или когда их требования несовместимы с общими. До этого момента дешевле и надёжнее держать всех на общей базе с хорошими индексами.

Помогает ли кэш масштабироваться?

Помогает, если ключ включает организацию и роль, а запрос уже исправлен. Кэш без таких условий прячет медленный запрос и создаёт риск, что один клиент получит ответ, сохранённый для другого.

Можно ли масштабировать, не переписывая продукт?

Чаще всего да: большинство узких мест снимается правкой запросов, индексов, вынесением задач в фон и ограничениями. Переписывание нужно, если в данных нет идентификатора организации или права проверяются в интерфейсе, а не на сервере. Это видно на обследовании.

Сколько стоит масштабирование SaaS-продукта?

Обследование стоит 200 000 ₽ (350 000 ₽ при нескольких системах). Дальше пилот на узком месте — 150 000–400 000 ₽, работы в рамках вывода в эксплуатацию — от 1 500 000 ₽ этапами по 300 000–700 000 ₽. Точная цена зависит от результатов обследования.

Вы проводите нагрузочное тестирование?

Мы готовим испытания на тестовом стенде и разбираем результаты. Нагрузочные атаки на боевую систему и защиту от DDoS не делаем. Нагрузочные испытания входят в вывод в эксплуатацию.