Короткий ответ
Нужно разбить изменение на обратно совместимые шаги: сначала миграция, добавляющая новую колонку без удаления старой, затем код, пишущий в обе колонки, затем полный rollout нового кода, использующего новую колонку, и только позже отдельная миграция, удаляющая старую — подход expand-contract.
Как это работает подробнее
при rolling deploy одновременно работают старая и новая версия, обращаясь к одной БД; прямое переименование одной атомарной миграцией сломает либо старые, либо новые инстансы, поэтому изменение схемы и кода разносят по времени.
Пример кода
migration.sql
ALTER TABLE orders ADD COLUMN customer_email_new VARCHAR(255);
-- новый код пишет в обе колонки, старый код продолжает работать с customer_email
-- после полного rollout и подтверждения стабильности, отдельным релизом:
ALTER TABLE orders DROP COLUMN customer_email;Что использовать на практике
- Рекомендация. шаги: 1) миграция добавляет новую колонку; 2) код пишет в обе колонки; 3) полный rollout кода, читающего только новую; 4) отдельная более поздняя миграция удаляет старую колонку, когда откат на предыдущий код уже не понадобится.
Подводные камни
- Риск. переименование одной миграцией одновременно с новым кодом — часть реплик упадёт с ошибками о несуществующей колонке; слишком быстро удалять старую колонку, не оставив времени на экстренный откат.