Переезды Goose для плавных изменений базы данных

Привет, дружище!

Сегодня давай поговорим о том, что такое миграции баз данных и почему они так важны. В современном мире неудивительно, что любые изменения в базе данных должны вноситься осторожно и в соответствии с определенным процессом. В идеале эти шаги должны быть интегрированы в наш CI/CD конвейер, чтобы все работало автоматически.

Вот наша повестка дня:

  1. В чем проблема?
  2. Как мы это исправим?
  3. Простой пример
  4. Более сложный пример
  5. Рекомендации
  6. Результаты
  7. Заключение

В чем проблема?

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

Основная проблема

Когда мы вносим «запланированные» и «гладкие» изменения в базу данных, нам нужно поддерживать доступность сервиса и выполнять требования SLA (чтобы пользователи не страдали от простоя или задержек). Представьте, что вы хотите изменить тип столбца в таблице с 5 миллионами пользователей. Если вы сделаете это «напрямую» (например, просто выполните ALTER TABLE без подготовки), таблица может заблокироваться на значительное время — и ваши пользователи останутся без сервиса.

Чтобы избежать таких головных болей, следуйте двум правилам:

  1. Применяйте миграции таким образом, чтобы не блокировать таблицу (или, по крайней мере, минимизировать блокировки).
  2. Если вам нужно изменить тип столбца, часто легче сначала создать новый столбец с правильным типом, а затем удалить старый.

Другая проблема: управление версиями и откаты

Иногда нужно откатить миграцию.

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

Как это исправить? Используйте правильные инструменты

Каждый язык и экосистема имеют свои собственные инструменты миграции:

  • Для Java, Liquibase или Flyway являются распространёнными.
  • Для Go популярным выбором является goose (тот, который мы рассмотрим здесь).
  • И так далее.

Goose: что это и почему это полезно

Goose — это легкий утилита Go, которая помогает вам управлять миграциями автоматически. Она предлагает:

  • Простота. Минимальные зависимости и прозрачная файловая структура для миграций.
  • Универсальность. Поддерживает различные драйверы БД (PostgreSQL, MySQL, SQLite и т.д.).
  • Гибкость. Пишите миграции на SQL или коде Go.

Установка Goose

Shell

 

Как это работает: Структура миграции

По умолчанию Goose ищет файлы миграции в db/migrations. Каждая миграция имеет следующий формат:

Shell

 

  • NNN – номер миграции (например, 001, 002, и т. д.).
  • После этого может быть любое описательное название, например init_schema.
  • Расширение файла может быть .sql или .go.

Пример SQL-миграции

Файл: 001_init_schema.sql:

SQL

 

Наш первый пример

Изменение типа столбца (Строка → Целое число)

Предположим, у нас есть таблица users с столбцом age типа VARCHAR(255). Теперь мы хотим изменить его на INTEGER. Вот как может выглядеть миграция (файл 005_change_column_type.sql):

SQL

 

Что здесь происходит:

  1. Миграция вверх

    • Мы изменяем столбец age на INTEGER. Клауза USING (age::INTEGER) указывает PostgreSQL, как конвертировать существующие данные в новый тип.
    • Обратите внимание, что эта миграция завершится неудачно, если есть какие-либо данные в столбце age, которые не являются числовыми. В этом случае вам понадобится более сложная стратегия (см. ниже).
  2. Обратная миграция

    • Если мы откатим изменения, вернем age к VARCHAR(255).
    • Мы снова используем USING (age::TEXT), чтобы преобразовать из INTEGER обратно в текст.

Вторые и сложные случаи: многоступенчатые миграции

Если столбец age может содержать неаккуратные данные (не только числа), безопаснее сделать это в несколько этапов:

  1. Добавьте новый столбец (age_int) типа INTEGER.
  2. Скопируйте допустимые данные в новый столбец, обрабатывая или удаляя недопустимые записи.
  3. Удалите старый столбец.
SQL

 

Чтобы обеспечить правильный откат, раздел Down просто зеркалит действия в обратном порядке.

Автоматизация — это ключ

Чтобы сэкономить время, действительно удобно добавить команды миграции в Makefile (или любую другую систему сборки). Ниже приведен пример Makefile с основными командами Goose для PostgreSQL.

Предположим:

  • DSN для базы данных — postgres://user:password@localhost:5432/dbname?sslmode=disable.
  • Файлы миграций находятся в db/migrations.
Shell

 

Как это использовать?

1. Создайте новую миграцию (SQL файл). Это создаст файл db/migrations/002_add_orders_table.sql.

Shell

 

2. Примените все миграции. Goose создаст таблицу schema_migrations в вашей базе данных (если она еще не существует) и применит любые новые миграции в порядке возрастания.

Shell

 

3. Отмените последнюю миграцию. Просто откатите последнюю.

Shell

 

4. Отмените все миграции (будьте осторожны в производственной среде). Полный сброс.

Shell

 

5. Проверьте статус миграции.

Shell

 

Пример вывода:

Shell

 

Итог

Используя инструменты миграции и Makefile, мы можем:

  1. Ограничить прямой доступ к производственной базе данных, внося изменения только через миграции.
  2. Легко отслеживать версии базы данных и откатывать их, если что-то пойдет не так.
  3. Поддерживать единую, последовательную историю изменений базы данных.
  4. Выполнять “плавные” миграции, которые не нарушат работающую производственную среду в мире микросервисов.
  5. Получить дополнительную проверку — каждое изменение пройдет через процесс PR и код-ревью (при условии, что у вас есть эти настройки).

Еще одно преимущество заключается в том, что легко интегрировать все эти команды в ваш CI/CD процесс. И помните — безопасность превыше всего.

Например:

YAML

 

Заключение и советы

Основные идеи настолько просты:

  • Делайте ваши миграции маленькими и частыми. Их легче рецензировать, тестировать и откатывать в случае необходимости.
  • Используйте один и тот же инструмент во всех средах, чтобы разработка, тестирование и продакшн были синхронизированы.
  • Интегрируйте миграции в CI/CD, чтобы не зависеть от ручного запуска кого-либо.

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

Удачи с миграциями!

Спасибо за внимание!

Source:
https://dzone.com/articles/goose-as-crucial-tool-for-your-service