İçeriğe geç
Все услуги

Масштабирование бэкенда

Масштабирование не сводится к серверам, оно начинается с поиска узкого места: измерение, оптимизация запросов, кэш, очереди и обратимый переход.

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

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

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

Как мы выстраиваем работу по масштабированию

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

Диагностика узкого места и измерение

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

Проектирование базы данных и оптимизация запросов

Под нагрузкой первой ломается почти всегда база данных, и причина обычно не в машине. Виноват запрос без индекса, запросы, повторяющиеся внутри цикла, или экран списка, у которого выборка растёт без ограничения. Добавление индекса без чтения плана запроса тоже остаётся догадкой: неверный индекс замедляет запись и просто перемещает проблему. Маркетплейс Anneekspres был построен с нуля на Python и Django поверх PostgreSQL, и фильтрация по категориям, поиск, а также управление остатками и заказами в панели продавца работают на одной и той же инфраструктуре. В каталожных системах, где преобладает фильтрация, стоимость лежит в запросе, а не в сервере: проект World Summer Schools собирает сотни программ в один поисковый каталог с фильтрами по возрасту, стране, типу программы и датам.

Слои кэша и инвалидация

Добавить кэш легко, трудность состоит в решении о том, что в него попадать не должно. Система, показывающая устаревшие данные, обходится дороже медленной, поэтому срок жизни каждой записи кэша и событие, которое её сбрасывает, фиксируются заранее. Наглядный пример дал Biletico: платформа была принята в работу, интерфейс, схема зала и платёжный поток собраны заново, а на стороне инфраструктуры кэширование поставили на Redis поверх связки Next.js и Node.js, данные при этом легли в MongoDB. На той же платформе схема зала на canvas может отражать заполненность в реальном времени. У нас охват кэша и то, что сознательно остаётся за его пределами, закрепляются отдельным письменным решением. Кэширующие структуры входили и в работу по производительности в проектах Welldone и Tegoly.

Очереди и асинхронная обработка на событиях

Пользовательский запрос должен выполнять только ту работу, которой пользователь ждёт. Формирование счетов, отправка уведомлений, расчёт отчётов и обращения к внешним сервисам к такой работе не относятся. После выноса из тракта запроса в очередь время отклика падает, а поток заказов остаётся живым при падении стороннего сервиса. В инфраструктуре Anneekspres очередь сообщений была построена на RabbitMQ, и страница проекта сообщает, что благодаря этой инфраструктуре система работает без перебоев под высокой нагрузкой. Платформа Lextum AI построена на микросервисной архитектуре с асинхронной обработкой через RabbitMQ и, как сообщает страница проекта, готова к корпоративной эксплуатации при высоком трафике. Очередь достаётся не бесплатно: потеря сообщения, двойная обработка и порядок доставки представляют собой три отдельных случая, каждый из которых приходится закрывать.

Постепенный переход от монолита к микросервисам

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

Нагрузочное тестирование и планирование мощности

Нагрузочный тест строится вокруг реального события в вашем деловом календаре, а не вокруг круглой цифры: минута открытия продажи билетов, старт кампании, начало сезона, день выплаты зарплаты. Цель записывается до теста, иначе результат потом можно выгодно истолковать с любой стороны. Измеряется не только то, выдержала ли система, но и то, в какой точке и с каким симптомом она ломается: без известной точки излома плана мощности не существует. Для проекта Anneekspres требование платформы, способной выдержать высокий трафик, было поставлено в самом начале работы. В проекте Togodo улучшения производительности обеспечили бесперебойную работу под высокой нагрузкой. Инфраструктура, построенная для World Summer Schools, спроектирована масштабируемой и готова к росту числа программ и пользователей.

Где системы ломаются на самом деле

Точкой излома редко оказывается мощность процессора. На практике выходит одно из четырёх мест. Первое занимает база данных: один запрос без индекса при росте нагрузки забивает пул соединений и ставит в ожидание всю систему. Второе занимает синхронный тракт: работа, которой пользователь не ждёт, оставленная в тракте запроса, замедляет вашу систему в ту же секунду, когда замедлился внешний сервис. Третьим идёт отсутствующий или неверно построенный кэш, причём второй опаснее первого, поскольку молча показывает неправильные данные. Четвёртым идёт конвейер выпуска: если выход в продакшен превращается в событие, найденная проблема остаётся в продакшене на часы или дни. Автоматизация CI/CD была построена на Jenkins в проектах Anneekspres, Biletico, Lextum AI, Welldone и World Summer Schools. Построение самого конвейера представляет собой отдельную работу и разбирается в услуге DevOps и CI/CD.

Сколько стоит масштабирование и где следует остановиться

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

Как проходит переход без простоя

Работа по масштабированию ведётся на живой системе, поэтому каждый шаг обязан быть обратимым. Порядок выглядит так. Сначала ставятся конвейер выпуска и наблюдаемость, потому что изменение без механизма отката вообще не пробуется. Изменения схемы проводятся в два этапа: новое поле добавляется, обе структуры какое-то время живут рядом, старое поле убирается только после того, как измерено его неиспользование. Пути чтения переносятся раньше путей записи, поскольку ошибку на стороне чтения можно откатить. Изменения открываются за флагом и сначала отдаются небольшой доле трафика. План отката пишется до выхода изменения в продакшен, и в нём поимённо указано, кто и при каком пороге откатывает. В проекте Biletico предпосылкой этого ритма служит структура, позволяющая тестировать и выпускать каждое обновление, а в проекте Anneekspres конвейер, обеспечивающий быстрое развёртывание.

Наши критерии выбора технологии

Выбор ограничен инструментами, которые мы держим в продакшене и которые после передачи сможет сопровождать кто-то другой. На стороне базы данных предпочтение по умолчанию остаётся за реляционным вариантом: Anneekspres, Lextum AI и World Summer Schools работают на PostgreSQL, Welldone на MySQL, Tegoly на MSSQL, а Togodo сочетает MSSQL и PostgreSQL. Там, где схема переменчива, мы переходим на документную сторону, и в этой группе Biletico и Tegoly работают с MongoDB. На стороне приложения при нагрузке, связанной с вводом и выводом, мы берём Node.js; при перевесе модели данных и административных экранов берём Python и Django; при определяющей роли корпоративных интеграций и ролевой структуры берём .NET. Слой кэша живёт на Redis, очередь на RabbitMQ, серверы на Ubuntu, конвейер выпуска на Jenkins. Решают три критерия, и мода в них не входит: кто будет сопровождать после передачи, находятся ли на рынке специалисты по этой технологии и может ли хостинг остаться в вашей собственной учётной записи.

Проекты, где применялась эта услуга

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

  • Anneekspres: маркетплейс товаров для мам и детей, построенный с нуля, с очередью сообщений на RabbitMQ, управлением данными на PostgreSQL и конвейерами Jenkins; система работает без перебоев под высокой нагрузкой.
  • Lextum AI: формирование документов, проверка договоров и одновременное редактирование для юридических команд на микросервисной архитектуре с асинхронной обработкой через RabbitMQ и управляемой SaaS-инфраструктурой на AWS.
  • Biletico: принятая в работу билетная платформа, где интерфейс, схема зала на canvas и платёжный поток были доведены до рабочего состояния, с кэшированием на Redis поверх Next.js и Node.js и данными в MongoDB.
  • Togodo: новые экраны, обмен сообщениями в реальном времени и уведомления, добавленные в приложение социальных событий; улучшения производительности обеспечили бесперебойную работу под высокой нагрузкой.
  • Welldone: сервисы на .NET, база MySQL, кэширующие структуры и масштабируемая серверная инфраструктура на Ubuntu, построенные для операций промышленной прачечной.
  • World Summer Schools: сотни программ летних школ, собранные в один поисковый каталог на облачной инфраструктуре поверх Next.js, .NET и PostgreSQL, готовой к росту числа программ и пользователей.
  • Tegoly: платформа электронной подписи, где скорость улучшена механизмами кэширования и оптимизированной конфигурацией серверов в Azure; работа по производительности снизила время загрузки страниц.
  • Terazzi: платформа в сфере строительства и декора, где выполнена оптимизация на стороне бэкенда и производительности, что подняло скорость работы сайта.

Преимущества

  • Сначала измерение: архитектурные изменения не предлагаются без профиля
  • Четыре источника узкого места: запрос, синхронный шаг, кэш, конвейер выпуска
  • План запроса и решение об индексах раньше, чем рост сервера
  • Кэш на Redis, очередь на RabbitMQ: работа без ожидания уходит из тракта запроса
  • Постепенный и обратимый переход с письменным планом отката
  • Нагрузочный тест строится вокруг реального события бизнеса, а не круглой цифры

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

Сколько длится работа по масштабированию бэкенда и как она оценивается?

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

Можно ли сделать это, не останавливая систему?

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

Что мы передаём по итогам работы?

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

Кто занимается сопровождением и наблюдением дальше?

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

Нужно ли масштабирование каждой замедлившейся системе?

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

Зачем трогать архитектуру, если можно взять сервер помощнее?

Чаще всего вы правы, и мы сами это рекомендуем. Одна машина побольше выходит дешевле и быстрее распределённой архитектуры и не добавляет эксплуатационной нагрузки. У этого варианта есть два предела: после определённого размера цена перестаёт расти линейно, а одна машина остаётся единственной точкой отказа. В отчёте о диагностике оба порога описаны цифрами, поэтому решение принимается не на глаз.

Как мы предоставляем эту услугу

Обсудим ваш проект

Как применить эту услугу к вашему проекту?

Заполните форму заявки для бесплатной 30-минутной консультации.