MAATRIX / Блог / Фронт, бэкенд и база на трёх серверах: с какого момента усложнение окупается

Фронт, бэкенд и база на трёх серверах: с какого момента усложнение окупается

MAATRIX

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

Что меняется по сравнению с состоянием «база отдельно, остальное вместе»

После выноса базы у вас, скорее всего, осталась связка «веб-сервер плюс серверная логика на одной машине» — nginx отдаёт статику и проксирует запросы в приложение (Node.js, Python/Gunicorn, PHP-FPM) через unix-сокет или localhost. Это уже не монолит: база не конкурирует с остальным за память и диск, а сеть до неё, скорее всего, уже настроена — если нет, стоит сначала закрыть это, а не открывать базу наружу по IP, об этом отдельно в статье про приватную сеть между своими серверами.

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

Технически это выглядит так: собранная статика (build React/Vue/Angular или SSR с минимальной логикой) уезжает на сервер с nginx или сразу в объектное хранилище с CDN — отдельный сервер под чистую статику может вообще не понадобиться. Бэкенд остаётся отдельным процессом на своей машине, слушает порт API и общается с базой по приватной сети. Фрагмент nginx на фронтенд-сервере, который теперь проксирует API-запросы не на localhost, а на другой хост:

location /api/ {
    proxy_pass http://10.10.0.12:8000/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

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

Независимое масштабирование: где выигрыш настоящий

Главный заявленный плюс полного разнесения — каждый компонент можно масштабировать под свой профиль нагрузки, не переплачивая за остальные. Эффект реальный, но выигрыш у компонентов разный по величине.

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

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

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

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

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать VPS

Независимый деплой без риска для остальных частей

Второй реальный плюс — деплой одного компонента больше не может случайно затронуть остальные. Пока фронтенд и бэкенд жили на одной машине, обновление одного из них теоретически могло задеть второй, если конфигурация была не изолирована: неудачный nginx -t, забытый reload, конфликт версий зависимостей (типичный случай — обновление системного Node.js для бэкенда ломает сборочный тулчейн фронтенда, который требовал другую версию).

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

Оговорка: тот же эффект изоляции можно получить дешевле — через отдельные systemd-юниты, контейнеры или раздельные каталоги с чёткими правами доступа на одном сервере, без физического разнесения на разные машины. Полное разнесение даёт максимальную изоляцию (в том числе по ресурсам — сборка фронтенда не отнимет CPU у бэкенда в пиковый момент), но не единственный способ разделить деплой-циклы. Если цель именно в независимости деплоя, стоит спросить, не будет ли контейнеризация на одном сервере достаточным решением при меньшей цене.

Чистые границы ответственности — но только если есть кому их проводить

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

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

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

Цена усложнения: втрое больше поверхности обслуживания

Три сервера вместо одного (или вместо двух после выноса базы) — это не абстрактная «сложность», а конкретный список операционных задач, который увеличивается кратно, а не на треть.

Мониторинг: вместо одной точки — три, каждая со своими алертами на диск, память, CPU, доступность; в Prometheus это три target'а вместо одного и три дашборда, которые нужно уметь читать вместе, когда что-то ломается на стыке.

Обновления безопасности: три ОС, которые нужно патчить, обычно с разным стеком — nginx и, может, Node для сборки на фронтенд-сервере, рантайм приложения на бэкенд-сервере, СУБД со своим циклом обновлений на сервере базы. У каждого свой набор пакетов и свои CVE, за которыми нужно отдельно следить.

Резервное копирование: раньше один бэкап-скрипт на один сервер, теперь минимум три конфигурации, даже если инструмент общий (Borg, restic): фронтенду обычно достаточно бэкапить конфиги (сборка воспроизводится из репозитория через CI), бэкенду — код и конфиги, базе — полноценный дамп с проверкой целостности и отдельным ретеншеном. Смешивать эти политики в одну неправильно.

Доступ и секреты: SSH-ключи, переменные окружения, TLS-сертификаты размножаются на три места, и рассинхрон между ними (протухший сертификат на одном сервере при живом на другом) — реальный источник инцидентов.

Таблица для ориентира, что кратно вырастает при переходе с одного/двух серверов на три:

Задача1-2 сервера3 сервера
Точек мониторинга1-23
Циклов патчинга ОС1-23
Конфигураций бэкапа1-2 (часто общая)минимум 3, разные политики
Мест хранения SSH-доступа/секретов1-23
Сетевых переходов на запрос пользователя1 (или 2 с базой)2-3

Для команды из одного-двух человек это не «немного больше работы» — это утроение количества мест, где что-то может незаметно устареть, если руки не доходят вовремя. Тот же эффект применительно к бюджету, а не времени, разобран в статье про то, что будет с бюджетом на инфраструктуру, когда команда вырастет вчетверо — рост числа операционных единиц почти никогда не бывает бесплатным, даже когда номинальная мощность серверов не меняется.

Сетевые издержки: задержка и новая категория отказов

До разнесения запрос доходил от nginx до процесса приложения через unix-сокет или localhost — доли миллисекунды, которыми можно пренебречь. После разнесения цепочка выглядит так: пользователь → фронтенд-сервер → бэкенд-сервер → сервер базы → и обратно тем же путём. Каждый переход между серверами — уже не локальный вызов, а сетевой запрос со своей задержкой, и если серверы стоят не в одном дата-центре или приватной сети с низкой задержкой, разница может быть не в разы, а на порядки — подробно разобрано в статье про разницу между задержкой внутри дата-центра и задержкой между регионами: для «разговорчивой» архитектуры с несколькими последовательными вызовами на запрос эта разница ощущается напрямую во времени ответа.

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

  • DNS или resolve имени бэкенд-сервера от фронтенда — если резолвер моргнул или закешировал устаревший адрес, фронтенд стучится в пустоту, хотя оба сервера живы;
  • firewall-правила теперь нужны на трёх машинах, и ошибка в любом наборе рвёт цепочку — например, забытое правило для нового порта после обновления бэкенда;
  • таймауты между сервисами нужно настраивать явно (proxy_connect_timeout, proxy_read_timeout в nginx, таймауты клиента к базе) — раньше локальный вызов не мог «зависнуть» на сетевом уровне;
  • при недоступности бэкенд-сервера раньше не было «сайт не отвечает» вообще, а теперь фронтенд может остаться живым, но с ошибками API — отдельный сценарий, требующий отдельной обработки на стороне интерфейса.

Ни один из этих пунктов не фатален — все решаемы стандартными средствами (мониторинг DNS, явные таймауты, firewall по приватной сети). Но это конкретная дополнительная работа, которая появляется в момент разнесения и не была нужна, пока всё жило на одном сервере.

Критерий окупаемости: когда усложнение оправдано

Собрав плюсы и цену вместе, практический критерий получается простым и проверяемым — без «это же стандартная лучшая практика» в качестве аргумента.

Разнесение на три сервера окупается, если верно хотя бы одно из двух:

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

Конкретный компонент объективно упирается в масштабирование, и это подтверждено метриками, а не предположением. Чаще всего это база — тем же методом, что при выносе базы на отдельный сервер: смотреть на iowait, своп, конкуренцию за буферный пул, а не выносить превентивно, потому что «так правильно». Реже это бэкенд, который упирается в CPU под собственной нагрузкой независимо от статики. Крайне редко — сам фронтенд, потому что раздача статики почти всегда дешевле по ресурсам, чем логика и база.

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

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

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать VPS

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

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

Нужен ли отдельный сервер под статический фронтенд, или можно сразу в объектное хранилище с CDN?

Для полностью статичной сборки (SPA без серверного рендеринга) отдельный VPS под nginx часто избыточен — объектное хранилище с CDN решает раздачу статики дешевле и без забот о патчинге ОС этого слоя. Отдельный сервер имеет смысл, если фронтенду нужна логика на своей стороне (SSR, edge-функции) или инфраструктурная политика требует держать всё на своих серверах.

Можно ли сделать независимый деплой без физического разнесения на разные серверы?

Да — контейнеризация или отдельные systemd-юниты с чёткими правами доступа на одном сервере дают значительную часть той же изоляции по деплою, но не изолируют ресурсы (CPU, память, диск) так же полно, как физически разные машины.

С чего начинать, если разносить не всё сразу, а по одному компоненту?

С того, для которого уже есть конкретное обоснование по метрикам или по конфликтам деплоя — не по порядку из методички. Если это база — она, скорее всего, уже вынесена, раз вы читаете эту статью; следующий по частоте кандидат — бэкенд, если он упирается в CPU или память отдельно от статики.

Разнесение на три сервера увеличивает счёт за инфраструктуру втрое?

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

Если команда через полгода вырастет и разнесение всё равно понадобится — не проще ли сделать сразу?

Издержка на перенос, когда для него появляется реальная причина, обычно ниже, чем полгода жить с утроенной операционной нагрузкой без соответствующей выгоды. Разнесение — в первую очередь конфигурация (сеть, деплой-скрипты, DNS), а не переписывание кода, если приложение изначально не завязано жёстко на локальные пути.

Обсудить статью, задать вопрос или начать новую тему

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

Перейти в сообщество →