Переезд с одного VPS на два: разделяем базу и приложение
Если проект начинался с одного VPS, где вместе крутятся веб-приложение и база данных, рано или поздно наступает момент, когда обоим стало тесно на одном железе. Сайт подтормаживает не от роста трафика, а потому что тяжёлый SQL-запрос съедает CPU, который нужен приложению, а перезапуск веб-сервера после деплоя иногда утаскивает за собой и базу. Разделение на два сервера — типичный первый шаг масштабирования, и сделать его можно спокойно, без даунтайма в полдня и без риска потерять данные, если действовать по понятному плану.
Содержание
Зачем разделять приложение и базу данных
Пока проект маленький, совмещённая схема удобна: один сервер, один счёт, минимум администрирования. Проблемы начинаются, когда нагрузка растёт неравномерно.
Конкуренция за ресурсы. CPU и память на сервере общие для всех процессов. Тяжёлый аналитический запрос к базе или полное сканирование большой таблицы забирают ядра процессора, которые в этот момент нужны PHP-FPM или Node.js для обработки запросов пользователей. И наоборот: всплеск трафика к приложению (например, после рекламной рассылки) может вытеснить из кэша страниц данные базы и создать давление на дисковый ввод-вывод. На одном сервере эти два процесса физически не могут получить пиковую производительность одновременно — они делят одну и ту же память под файловый кэш, один и тот же I/O к диску, одни и те же ядра.
Изоляция сбоев. Если СУБД на общем сервере упирается в лимит max_connections или уходит в своп из-за нехватки памяти, зависает не только база — начинает тормозить или падать всё приложение, потому что делит с ней ядро и оперативную память. И обратная ситуация: утечка памяти в приложении или неудачный деплой может увести в OOM весь сервер вместе с работавшей до этого стабильно базой. Разнеся компоненты по разным серверам, вы получаете реальную изоляцию: если легло приложение — база продолжает отвечать и данные не теряются, а восстановление сводится к перезапуску одного сервиса, а не разбору того, что случилось с обоими сразу.
Независимое масштабирование и настройка. У базы данных и у веб-приложения принципиально разные профили нагрузки. Базе обычно важнее память под кэш страниц и быстрый диск (NVMe), приложению — количество ядер CPU. Разведя их по разным серверам, конфигурацию каждого можно подбирать под его специфику, не идя на компромисс: под базу — сервер с упором в RAM и диск, под приложение — с упором в CPU. Апгрейдить и масштабировать тоже можно раздельно: выросла нагрузка на чтение из базы — добавили реплики или подняли RAM только на сервере БД, не трогая сервер приложения.
Дальше — пошаговый план, как переехать с одного VPS на два без хаоса.
Шаг 1. Готовим сервер под базу данных заранее
Первая и самая частая ошибка — сначала переносить данные, а потом разбираться с версией СУБД на новом сервере. Делайте наоборот: полностью подготовьте новый сервер под базу заранее, до того как трогать боевые данные.
Первым делом узнайте точную версию СУБД на старом сервере:
# PostgreSQL
psql -V
# или изнутри psql:
SELECT version();
# MySQL / MariaDB
mysql -V
# или изнутри клиента:
SELECT VERSION();
Критично важно поставить на новом сервере ту же версию, а не «последнюю стабильную» — расхождение мажорных версий PostgreSQL или MySQL может сломать совместимость дампа, формат хранения данных или поведение репликации. Если на старом сервере PostgreSQL 15, ставьте PostgreSQL 15, а не 17 «раз уж переезжаем». Мажорный апгрейд СУБД — отдельная задача, её стоит делать до или после переезда, но не одновременно с ним, чтобы не путать два источника возможных проблем.
Для Ubuntu 24.04 и PostgreSQL это выглядит так:
sudo apt update
sudo apt install -y postgresql-15 postgresql-contrib-15
Для MySQL — важно поставить не просто mysql-server из дефолтного репозитория (там может оказаться другая мажорная версия), а явно указанную через официальный APT-репозиторий MySQL или MariaDB, если версии на старом сервере отличаются от того, что предлагает дистрибутив по умолчанию.
На этом же шаге настройте на новом сервере базовые параметры (кодировку, timezone, локаль) идентично старому серверу — расхождение в encoding базы данных всплывает не сразу, а в момент, когда в данные попадает нестандартный символ.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать VPSШаг 2. Настраиваем приватную сеть между серверами
До переноса данных нужно решить, как приложение будет достучаться до базы на новом сервере. Худший вариант — открыть порт СУБД (5432 или 3306) на публичный IP с надеждой на пароль понадёжнее. Это ровно та ошибка, которая регулярно всплывает в логах брутфорс-сканеров: подробнее о том, чем это грозит, — в статье база данных, открытая наружу.
Правильная схема — приватная сеть или VPN между двумя серверами, через которую и ходит трафик к базе, а публичный доступ к порту СУБД закрыт вовсе. Варианты:
- Приватная сеть провайдера (если оба сервера в одном дата-центре одного провайдера и такая сеть предусмотрена) — самый простой и низколатентный вариант.
- WireGuard между серверами, если приватной сети провайдера нет или серверы у разных провайдеров/в разных локациях.
Минимальная настройка WireGuard между двумя серверами:
# на обоих серверах
sudo apt install -y wireguard
wg genkey | tee privatekey | wg pubkey > publickey
Конфиг /etc/wireguard/wg0.conf на сервере базы данных (пример, приватная подсеть 10.10.10.0/24):
[Interface]
Address = 10.10.10.1/24
PrivateKey = <приватный_ключ_сервера_БД>
ListenPort = 51820
[Peer]
PublicKey = <публичный_ключ_сервера_приложения>
AllowedIPs = 10.10.10.2/32
И зеркально на сервере приложения, с адресом 10.10.10.2/24 и AllowedIPs = 10.10.10.1/32. После wg-quick up wg0 на обоих серверах приложение обращается к базе по адресу 10.10.10.1, а не по публичному IP.
Дальше — фаервол на сервере базы данных. Правило простое и не подлежит компромиссам: порт СУБД должен принимать подключения только с IP сервера приложения (в данном случае — с адреса из приватной сети), и ни с какого другого:
# UFW: разрешаем PostgreSQL только с сервера приложения по приватной сети
sudo ufw allow from 10.10.10.2 to any port 5432 proto tcp
sudo ufw deny 5432
Убедитесь, что сама СУБД тоже слушает нужный интерфейс, а не 0.0.0.0 без ограничений — в postgresql.conf укажите listen_addresses = 'localhost,10.10.10.1', а не '*'. Про частые ошибки в самих правилах фаервола, из-за которых доступ теряют случайно, а не специально, — в статье ошиблись в правиле firewall и потеряли доступ.
Шаг 3. Переносим данные: дамп или репликация
Способ переноса данных зависит от размера базы и допустимого простоя.
| Способ | Когда подходит | Простой |
|---|---|---|
Дамп и восстановление (pg_dump/mysqldump) | Небольшая база (до нескольких ГБ), простой в несколько минут не критичен | От минут до десятков минут — на время снятия дампа и загрузки |
| Репликация (потоковая для PostgreSQL, бинлог для MySQL) | Большая база, простой нужно свести к секундам | Секунды — только на переключение после того, как реплика догнала мастер |
Для небольшой базы — классический дамп-восстановление. На старом сервере:
# PostgreSQL
pg_dump -U postgres -Fc mydb > mydb.dump
# MySQL
mysqldump -u root -p --single-transaction --routines --triggers mydb > mydb.sql
Передайте дамп на новый сервер по приватной сети (scp через адрес 10.10.10.1) и восстановите:
# PostgreSQL
pg_restore -U postgres -d mydb --create mydb.dump
# MySQL
mysql -u root -p mydb < mydb.sql
На время снятия дампа и переноса приложение либо переводится в режим обслуживания, либо продолжает писать в старую базу — тогда после восстановления нужен второй, инкрементальный перенос изменений за это время (для небольших баз проще просто остановить запись на короткое окно).
Для большой базы, где остановка на дамп неприемлема, — репликация. Идея: поднять на новом сервере реплику старой базы, дождаться, пока она догонит мастер (лаг близок к нулю), и только тогда переключить приложение — простой сводится к секундам на само переключение. Пошаговая настройка потоковой репликации PostgreSQL — в статье как установить и настроить репликацию PostgreSQL на VPS. Общий план подготовки к переносу данных между серверами, включая проверку целостности после переноса, разобран в статье миграция базы данных между серверами.
После любого способа переноса обязательно сверьте контрольные показатели: количество строк в ключевых таблицах, размер базы, дату последней записи — это быстрее, чем построчная сверка, и ловит большинство проблем переноса.
# количество строк в таблице — сравнить на старом и новом сервере
SELECT count(*) FROM orders;
Шаг 4. Переключаем приложение на новый адрес базы
Когда данные на новом сервере готовы и проверены, остаётся изменить конфигурацию приложения. До переезда строка подключения указывала на localhost или на unix-сокет — теперь база находится на другом сервере и доступна по внутреннему адресу приватной сети.
Пример для .env-файла:
# было
DB_HOST=localhost
DB_PORT=5432
# стало
DB_HOST=10.10.10.1
DB_PORT=5432
Для приложений, которые подключались через unix-сокет (это быстрее, чем TCP на localhost, поэтому иногда выбирался по умолчанию), обязательно проверьте, что конфиг явно переключён на TCP-подключение по IP — иначе после отключения локальной базы приложение будет пытаться достучаться до сокета, которого больше нет, и упадёт с ошибкой подключения, а не просто «медленно поработает».
После смены конфига — рестарт приложения и проверка подключения к базе именно с сервера приложения (не со своей машины, где могут быть другие маршруты):
# с сервера приложения
psql -h 10.10.10.1 -U app_user -d mydb -c "SELECT 1"
Если подключение не проходит — сначала проверьте фаервол на сервере базы (шаг 2), затем pg_hba.conf/bind-address, и только потом саму строку подключения в приложении: в 9 случаях из 10 проблема именно в сети или в правилах доступа, а не в приложении.
Шаг 5. Проверяем производительность и держим план отката
Разделение серверов решает проблему конкуренции за ресурсы, но добавляет новый фактор — сетевую задержку между приложением и базой. Даже в приватной сети внутри одного дата-центра каждый запрос к базе теперь проходит через дополнительный сетевой переход вместо обращения к localhost, и эта задержка не равна нулю, хотя обычно и небольшая. Насколько именно она заметна — сильно зависит от количества запросов на страницу: если на одну страницу уходит один SQL-запрос, лишний миллисекунды-две почти не видны; если на страницу их сто (N+1-паттерн в ORM), та же добавка умножается на сто и становится ощутимой.
Проверьте это явно, а не понадеявшись, что «в одном ДЦ разницы не будет»:
# сетевая задержка между серверами по приватной сети
ping -c 20 10.10.10.1
И сравните время отклика ключевых страниц приложения до и после переезда — под той же нагрузкой, тем же тестовым сценарием. Если после разделения страницы, которые делают много последовательных запросов к базе, ощутимо просели — это сигнал не откатывать переезд, а поискать N+1-запросы и заменить их на один запрос с JOIN или на пакетную выборку. О похожем случае, когда перенос базы неожиданно обернулся тормозами именно из-за таких деталей, — в статье перенесли базу и получили тормоза.
Отдельно держите план отката — на случай, если что-то пошло не так уже после переключения:
- Не удаляйте старую базу сразу. Оставьте её нетронутой на старом сервере минимум несколько дней после переезда — это самый дешёвый и надёжный откат: просто верните
DB_HOSTобратно наlocalhost. - Сохраните дамп, снятый перед переносом, отдельно от обоих серверов (локально или в объектное хранилище) — на случай, если понадобится восстановить именно то состояние.
- Зафиксируйте контрольные точки (те же количество строк, размер базы, дата последней записи из шага 3) — если после недели работы на новой схеме что-то не сходится, будет с чем сравнить.
- Мониторьте первые дни особенно внимательно — ошибки подключения, рост времени ответа, лимиты соединений — чтобы заметить проблему на этапе «неудобно», а не «критично».
Только когда новая схема отработала стабильно хотя бы неделю под реальной нагрузкой, старую базу на бывшем совмещённом сервере можно удалить, а сам сервер — переиспользовать или отказаться от него.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать VPSНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Обязательно ли использовать VPN, если оба сервера в одном дата-центре одного провайдера?
Если провайдер предоставляет приватную сеть между своими серверами в пределах дата-центра — используйте её, она проще и без накладных расходов на шифрование WireGuard. VPN нужен, когда приватной сети провайдера нет или серверы физически разнесены (разные ДЦ, разные провайдеры).
Что делать, если версии СУБД на старом и новом сервере всё же различаются?
Дамп через pg_dump/mysqldump обычно переносится между соседними минорными и даже мажорными версиями, но чем больше разрыв, тем выше риск несовместимости отдельных функций или расширений. Правильный порядок — сначала завершить переезд на идентичной версии, затем отдельным шагом делать плановый апгрейд СУБД, а не совмещать оба риска в одной операции.
Нужно ли сразу переносить и резервное копирование базы на новый сервер?
Да, причём до отключения старой схемы — настройте бэкапы (например, pg_dump по расписанию или pgBackRest/Percona XtraBackup) на новом сервере сразу после переноса данных, а не откладывайте на «потом», иначе первые дни после переезда база остаётся без свежих резервных копий.
Как понять, что базе действительно нужен отдельный сервер, а не просто больше памяти на текущем?
Проверьте через top/htop и мониторинг СУБД, кто именно упирается в лимит: если и приложение, и база одновременно близки к 100% CPU или к пределу памяти в часы пик — добавление ресурсов на одном сервере лечит симптом ненадолго, а разделение убирает саму конкуренцию за ресурс.
Сколько по времени занимает весь переезд для базы среднего размера (10-30 ГБ)?
Подготовка нового сервера и сети обычно занимает больше времени, чем сам перенос данных — рассчитывайте на подготовку заранее, без спешки, а окно фактического простоя при дамп-подходе для такого объёма — от нескольких минут до получаса, в зависимости от скорости диска и сети.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →