Миграция базы данных сайта
Миграция БД — технически самый рискованный этап любой инфраструктурной работы. Потеря данных или недоступность сайта во время миграции имеют прямые финансовые последствия. Подход зависит от размера БД, допустимого downtime и требований к согласованности данных.
Стратегии по downtime
Maintenance window (простейший): сайт в режиме обслуживания → дамп → перенос → запуск. Downtime = время дампа + переноса. Приемлемо для БД до 10 GB в ночное время.
Online migration: репликация с source на target, минимальный downtime только для переключения. Для MySQL — Percona XtraBackup или binlog replication. Для PostgreSQL — pglogical или pg_basebackup + WAL shipping.
Blue-Green: параллельная БД, приложение пишет в обе, затем переключение. Сложнее, но нулевой downtime.
MySQL: безопасный дамп и восстановление
# Дамп с блокировкой для консистентности
mysqldump \
--single-transaction \
--routines \
--triggers \
--events \
--hex-blob \
--default-character-set=utf8mb4 \
-u root -p mysite_db \
| gzip > /backup/mysite_$(date +%Y%m%d_%H%M%S).sql.gz
# Размер до сжатия (для оценки времени)
mysql -u root -p -e "
SELECT
table_schema AS 'Database',
ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS 'Size (MB)'
FROM information_schema.tables
WHERE table_schema = 'mysite_db'
GROUP BY table_schema;
"
# Восстановление
gunzip < /backup/mysite_20241201_030000.sql.gz | mysql -u root -p new_db
PostgreSQL: pg_dump и pg_restore
# Кастомный формат (быстрее, сжатый, параллельное восстановление)
pg_dump \
-U postgres \
-d mysite_db \
-F custom \
-f /backup/mysite_$(date +%Y%m%d).dump \
--verbose
# Параллельное восстановление
pg_restore \
-U postgres \
-d new_db \
-j 4 \ # 4 параллельных потока
--verbose \
/backup/mysite_20241201.dump
# Проверка целостности
psql -U postgres -d new_db -c "SELECT COUNT(*) FROM users;"
psql -U postgres -d new_db -c "SELECT COUNT(*) FROM posts;"
Online миграция PostgreSQL с минимальным downtime
# 1. Настраиваем репликацию через pglogical
# На source
psql -c "CREATE EXTENSION pglogical;"
psql -c "SELECT pglogical.create_node(node_name := 'provider', dsn := 'host=source dbname=mysite user=replication');"
psql -c "SELECT pglogical.create_replication_set('all_tables');"
psql -c "SELECT pglogical.replication_set_add_all_tables('all_tables', ARRAY['public']);"
# На target
psql -c "CREATE EXTENSION pglogical;"
psql -c "SELECT pglogical.create_node(node_name := 'subscriber', dsn := 'host=target dbname=mysite_new user=replication');"
psql -c "SELECT pglogical.create_subscription(
subscription_name := 'sub_mysite',
provider_dsn := 'host=source dbname=mysite user=replication password=secret'
);"
# 2. Ждём синхронизации
psql -c "SELECT * FROM pglogical.show_subscription_status();"
# 3. Downtime: останавливаем запись, переключаем приложение на новую БД
# Downtime = секунды, не часы
Валидация после миграции
# Сравниваем количество строк в критических таблицах
for table in users posts orders products; do
src=$(mysql -h source -u root -p -se "SELECT COUNT(*) FROM mysite.$table")
dst=$(mysql -h target -u root -p -se "SELECT COUNT(*) FROM mysite.$table")
if [ "$src" != "$dst" ]; then
echo "MISMATCH: $table: $src vs $dst"
else
echo "OK: $table: $src rows"
fi
done
Размеры и ориентировочное время
| Размер БД | Дамп + перенос | pg_restore (параллельно) |
|---|---|---|
| до 1 GB | 2–10 мин | 1–5 мин |
| 1–10 GB | 10–60 мин | 5–20 мин |
| 10–100 GB | 1–8 часов | 30 мин – 3 часа |
| 100 GB+ | Online migration | — |
Полная миграция с планированием, тестовым прогоном и rollback-планом — 1–5 дней в зависимости от сложности.







