Онлайн-миграция схемы MySQL: где ломается прод
Изменение структуры таблицы без простоя кажется рутинной операцией, пока ALTER не встречается с живой нагрузкой. MySQL удерживает метаданные таблицы до конца перестройки: пока переписываются миллионы строк, входящие запросы ждут освобождения блокировки. Деградация сервиса под нагрузкой начинается раньше, чем сама операция завершится.
Блокировки таблиц в проде — только первая грань. Долгая перестройка держит открытую транзакцию и раздувает журнал отката, а таймауты при долгой перестройке рвут обмен с репликами: отставание растёт, и часть трафика читает устаревшие данные. Пользователь видит не ошибку миграции, а замедлившийся сервис.
Отдельный класс отказов — расхождение данных на копиях. Перестройка через таблицу-двойник и триггеры переносит строки порциями, и порция, потерянная при переключении или конфликте уникальных ключей, остаётся только в старой версии таблицы. Миграция выглядит успешной, а сверка счётчиков показывает расхождение.
Инструмент pt-online-schema-change снимает большую часть этих рисков: копирует таблицу порциями, следит за отставанием копий и переключает данные переименованием. Но поведение задают параметры — размер порции, пауза при отставании, допустимая нагрузка на диск; выставленные наугад, они роняют базу сильнее, чем одиночный ALTER.
Онлайн-миграция схемы MySQL — управляемый процесс, а не нажатие кнопки: ему предшествуют замеры, репетиция на копии и план отката. Разбираем, где именно ломается прод и как это закрывается.
Что даёт аккуратная перестройка таблиц без остановки
Обычный ALTER TABLE на большой таблице выстраивает очередь запросов за метаданными блокировки: пока идёт перестройка, чтения и записи ждут, а на нагруженном сервисе это выглядит как всплеск таймаутов у клиентов. Перестройка таблиц без остановки сервиса устроена иначе: Percona Toolkit создаёт теневую копию с целевой структурой, переносит строки порциями и синхронизирует изменения через триггеры, пока приложение продолжает писать в исходную таблицу.
Блокировка остаётся только на финальном переключении — короткое переименование, которое не успевает накопить очередь запросов. Это и есть устранение отказов из-за блокировок: класс ошибок, где приложение ждёт освобождения таблицы дольше, чем позволяет его таймаут, не возникает вовсе. Окно обслуживания сокращается с часов планового простоя до нескольких секунд, и то лишь при условии, что переключение укладывается в регламент.
Предсказуемое время работ даёт управляемая скорость переноса: между порциями выдерживается пауза, а при росте задержки на копии процесс автоматически приостанавливается. Снижение нагрузки на копии базы достигается тем же механизмом — реплики не отстают от мастера, поэтому отчёты и аналитика продолжают читать актуальные данные, а не догоняют источник после завершения работ.
На выходе заказчик получает таблицу с целевой структурой, план отката, подготовленный до запуска, и журнал переноса: объём строк, точки пауз, длительность финальной замены. Сроки по крупной таблице считаются заранее по объёму и скорости переноса, а не выясняются в момент простоя — это и превращает миграцию из риска в планируемую работу.
Способы перестроить таблицу: сравнение подходов и ограничений
Выбор способа определяется тремя параметрами: объём таблицы, допустимое время недоступности записи и характер нагрузки. Онлайн-перестройка через промежуточную копию — это pt-online-schema-change из Percona Toolkit — создаёт рядом таблицу с новой структурой, копирует строки порциями и вешает триггеры на источник, поэтому изменения из приложения попадают сразу в обе таблицы. На финальном шаге имена меняются местами, и блокировка записи укладывается в миллисекунды — обычно её не замечают ни пользователи, ни фоновые задачи.
Границы у подхода тоже конкретные. Таблица без первичного или уникального ключа не обрабатывается — это отсекает часть исторических таблиц. Копия занимает столько же места, сколько источник, а при плотной записи догон изменений может отставать от триггеров: тогда работа прерывается, и её переносят в окно обслуживания.
| Подход | Когда подходит | Ограничения |
|---|---|---|
| Онлайн-перестройка через промежуточную копию | Есть первичный ключ, запись нельзя останавливать, таблица живёт под круглосуточной нагрузкой | Копия удваивает место, нет уникального ключа — не запускается, при плотной записи догон отстаёт |
| Перенос на новую таблицу с догрузкой | Меняется тип ключа, схема секционирования или структура переписывается глубоко | Нужен код, читающий обе таблицы, и время на сверку; переключение приложений согласуется |
| Плановое окно обслуживания | Малая или средняя таблица, есть согласованное время простоя | Запись останавливается, часть запросов получает ошибку, нужен подготовленный слепок для отката |
Практическое правило: до нескольких миллионов строк и умеренной записи — онлайн-способ; глубокая смена структуры — перенос на новую таблицу с последующей сверкой; небольшие таблицы дешевле и предсказуемее перестроить в плановое окно, когда запись останавливается на минуты.
Этапы работ: от аудита нагрузки до передачи базы
Порядок работ строят от нагрузки, а не от удобства окна: пока таблица открыта на запись, изменение конкурирует за блокировки, место и пропускную способность реплик. Каждый этап заканчивается проверяемым результатом, поэтому решение идти дальше принимается по цифрам, а не по ощущению.
- Аудит нагрузки на базу. Снимаем профиль за несколько суток: пиковые часы, доля операций записи, самые тяжёлые запросы, отставание реплик, размер и скорость роста целевых таблиц. На выходе — окно, в котором вмешательство безопасно.
- Схема проведения работ. Определяем, какое изменение нужно, пересобирается таблица целиком или меняется на месте, хватит ли места на диске, как поведут себя внешние ключи и триггеры. Здесь же появляется оценка длительности.
- Настройка миграции. Инструмент pt-online-schema-change переносит данные порциями, поэтому задаём размер порции, допустимое отставание реплик, порог аварийной остановки и контроль блокировок. Неверная настройка тормозит базу сильнее самого изменения.
- Пробный прогон. Прогоняем на копии промышленной базы с реальным объёмом: замеряем время, поведение триггеров, влияние на реплики. Это даёт фактические цифры вместо расчётов.
- Точка отката. Фиксируем способ и время возврата: исходная таблица остаётся нетронутой, снимок снят, возврат укладывается в окно. Откат проверяем до боевого запуска, а не после.
- Сверка целостности данных. Сравниваем количество строк и контрольные суммы до и после, проверяем индексы и внешние ключи. Новая схема входит в работу только при полном совпадении.
- Передача базы. Отдаём параметры, схему, регламент повторных изменений и пороги наблюдения, по которым дежурный увидит проблему раньше пользователей.
Опишите вашу базу и задачу — вернёмся с оценкой и планом по этим этапам.
Что остаётся у команды: состав поставки и документация
Работа заканчивается не в момент успешной миграции, а когда команда заказчика может повторить её без нас. Поэтому в поставку входят не только сам прогон, но и конфигурации, схемы связей между таблицами и регламенты — то, по чему следующий инженер пройдёт тот же путь и получит тот же результат.
- Рабочие конфигурации: параметры копирования данных, пороги допустимой нагрузки на сервер, лимиты ожидания блокировок и список таблиц-исключений — как файлы рядом с миграциями в проекте.
- Схемы зависимостей таблиц: какие внешние ключи, триггеры и связки «родитель — потомок» влияют на порядок работ, что переносить первым, а что ждать до последнего.
- Правила доступа: отдельная учётная запись с минимально достаточными правами, что именно нужно для создания триггеров и переключения, а что остаётся недоступным по умолчанию.
- Регламент повторных работ: пошаговый порядок для следующей миграции — от оценки размера таблицы и окна работ до проверки репликации и удаления служебных объектов.
- Документация по откату: как вернуть прежнюю схему, если переключение не прошло, какие объекты удалить и за какой срок состояние возвращается к исходному.
- Отчёт о прогоне: время обработки каждой таблицы, задержка репликации, число повторных попыток и точки, где потребовалось вмешательство инженера.
- Скрипты проверки: сверка числа строк и контрольных сумм до и после, чтобы результат подтверждался данными, а не словами.
Кейс: перевод крупной таблицы на новую структуру без простоя
Узкое место: перестройка под блокировкой
Таблица на 180 млн строк принимала несколько тысяч операций в секунду, и обычная смена типа ключевого поля с перестройкой индексов держала её под блокировкой целиком. Ближайшее окно давало около 40 минут недоступности на запись, смежным командам пришлось бы останавливать фоновые задачи, а часть запросов всё равно отваливалась по таймауту — порядка 0,3% операций терялось и разбиралось вручную.
Как прошло и чем закончилось
Использовали pt-online-schema-change из Percona Toolkit: инструмент заводит теневую копию таблицы, навешивает триггеры на изменения и переносит строки порциями, а при росте задержки репликации сам сбавляет темп. Копирование шло параллельно с рабочим трафиком, без окна простоя — вечерний пик прошёл без деградации, а переключение на новую структуру заняло доли секунды, блокировка только на подмену таблицы. После перехода сверили контрольные суммы по всем перенесённым порциям: расхождений ноль, возврат к исходной таблице оставался доступен до конца сверки.
| Метрика | До | После |
|---|---|---|
| Недоступность на запись | ~40 минут | доли секунды |
| Потерянные операции | ~0,3% | 0 |
| Сверка данных | выборочная, вручную | контрольные суммы по всем порциям |
| Поведение на пике | остановка фоновых задач | миграция сама сбавляла темп |
| Откат | восстановление из копии | возврат к исходной таблице |
Что делать, если в MySQL уже есть реплики и триггеры?
Уже развёрнутый контур с репликами миграции не мешает, но меняет порядок работ. Инструмент создаёт копию таблицы с новой структурой, наполняет её порциями и синхронизирует правки триггерами, а в конце подменяет исходную атомарным переименованием — реплики получают ту же последовательность из журнала.
Свои триггеры — первая загвоздка: по умолчанию инструмент останавливается, если на таблице уже есть триггеры, чтобы не сломать чужую логику. Ключ --preserve-triggers переносит их тела на новую таблицу, но проверьте, что они не ссылаются на старое имя явно — после подмены такие ссылки станут битыми.
Внешние ключи задают цену и окно риска. Режим rebuild_constraints пересобирает дочерние ограничения — дольше, зато без промежутка, когда ссылки висят на исчезнувшей таблице; drop_swap быстрее, но такое окно создаёт, а на связях с каскадным удалением требует отдельной проверки. Когда ключи смотрят и внутрь, и наружу, изменение прогоняют на копии контура целиком.
Отдельный риск — фильтры репликации: если служебная таблица-копия под них попадает, на реплике её не будет, подмена пройдёт «успешно», а структуры разъедутся, поэтому конфигурацию сверяют до старта, а порог --max-lag приостанавливает копирование при сильном отставании. Пока изменение структуры не дошло до всех реплик, приложение не должно читать новые колонки — на отстающей их ещё нет, отсюда отложенное чтение старых данных и ошибки. Работаем одним изменением за проход: прогон, подмена, сверка структуры на мастере и каждой реплике, затем следующее.
Технические сомнения: вопросы, которые задают перед стартом
Перед перестройкой крупной таблицы на боевой базе всплывает один и тот же набор вопросов: сколько достанется живой нагрузке, что будет при обрыве, как поведут себя внешние ключи и триггеры, чем подтверждается результат. Ниже — ответы, которые обычно нужны до согласования окна.
Перестройка таблицы положит базу?
Копирование идёт порциями с паузами между ними. Задаются пороги по числу активных запросов и отставанию реплики: при превышении копирование останавливается и ждёт, пока база освободится. Прод получает добавку к нагрузке, а не просадку по времени ответа.
Что будет, если работу прервать?
В Percona Toolkit при остановке или ошибке инструмент убирает свои триггеры и временную таблицу, исходная остаётся нетронутой, продолжить можно с точки останова. Необратимо лишь финальное переключение таблиц — его держат коротким и делают в согласованное окно.
Внешние ключи и триггеры — что с ними?
Дочерние таблицы переключаются отдельным шагом, иначе внешние ключи продолжат смотреть на старую. Триггеры, висевшие на исходной таблице, во время копирования не срабатывают — их логику переносят заранее, иначе часть изменений теряется.
Как убедиться, что данные не потерялись?
После переключения сверяем число строк и контрольные суммы по диапазонам, отдельно — записи, изменённые при копировании. Расхождения разбираем до удаления временной таблицы: пока она на месте, откат ещё возможен.
А если копий базы несколько?
Реплики не наследуют перестройку — схему на каждой копии приводят своим проходом. Либо повторяем миграцию на каждой, либо пересобираем копию из резервной и догоняем её журналом изменений, если отставание допустимо.
Обсудим задачу: пришлём план работ и оценку
Чтобы вернуться с планом этапов работ и оценкой сроков, нам нужны вводные по вашей базе — не абстрактное «есть сервер с MySQL», а конкретика: целевые таблицы и их объём, движок хранения, наличие внешних ключей, триггеров и представлений, топология репликации, окно низкой нагрузки. Чем точнее исходные данные, тем меньше сюрпризов на боевом контуре: по ним заранее видно, где потребуется пересборка таблицы, а где достаточно переключения через переименование.
Что вы получаете после разбора задачи:
- План этапов работ с порядком действий: подготовка, пробный прогон на копии, миграция, проверка целостности данных, фиксация точки отката.
- Оценку сроков с разбивкой по этапам и пометкой, где нужно окно согласования с бизнесом.
- Схему отката: какие метаданные сохраняем и как вернуться к исходной таблице, если проверки не прошли.
- Перечень рисков под вашу конфигурацию: длительные блокировки, рост нагрузки на реплики, отставание подчинённых узлов.
- Набор метрик сопровождения: задержка репликации, число активных соединений, скорость обработки копируемых строк.
- Черновик регламента для дежурной смены: что делать при срабатывании сигналов и когда останавливать перенос.
Проверку проводим на вашем контуре — на копии боевой базы или стенде той же конфигурации, чтобы результат прогона переносился дальше без допущений и пересчётов.
Опишите задачу: какие таблицы трогаем, какая нагрузка в часы пик, есть ли окно для переключения. Вернёмся с планом этапов и оценкой сроков.







