Миграции схемы данных YDB с Flyway и распределенные блокировки

от автора

Привет, Хабр! Меня зовут Кирилл Курдюков, я разработчик YDB. Ранее мы рассматривали интеграцию YDB c Liquibase, теперь поговорим о результатах поддержки инструмента Flyway для управления миграциями схемы данных YDB.

Введение

Flyway — это инструмент для миграций схем баз данных с открытым исходным кодом. Он имеет расширения для различных систем управления базами данных (СУБД), включая YDB. Является таким же широко используемым и популярным инструментом для управления миграциями схем базы данных, как и Liquibase.

Flyway и Liquibase определяют, какие изменения уже были применены к базе данных, а какие еще не были. Для этого они ведут журнал выполненных миграций в самой базе данных.

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

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

Как использовать Flyway вместе с YDB

Чтобы использовать Flyway вместе с YDB в Java / Kotlin приложении или в Gradle / Maven плагинах, требуется установить зависимость расширения Flyway для YDB и YDB JDBC Driver:

Maven:

<!-- Set actual versions --> <dependency>     <groupId>org.flywaydb</groupId>     <artifactId>flyway-core</artifactId>     <version>${flyway.core.version}</version> </dependency>  <dependency>     <groupId>tech.ydb.jdbc</groupId>     <artifactId>ydb-jdbc-driver</artifactId>     <version>${ydb.jdbc.version}</version> </dependency>  <dependency>     <groupId>tech.ydb.dialects</groupId>     <artifactId>flyway-ydb-dialect</artifactId>     <version>${flyway.ydb.dialect.version}</version> </dependency>

Gradle:

dependencies {     // Set actual versions     implementation "org.flywaydb:flyway-core:$flywayCoreVersion"     implementation "tech.ydb.dialects:flyway-ydb-dialect:$flywayYdbDialecVersion"     implementation "tech.ydb.jdbc:ydb-jdbc-driver:$ydbJdbcVersion" }

Для работы с YDB через Flyway CLI требуется установить утилиту flyway любым из рекомендованных способов.

Затем Flyway нужно расширить диалектом YDB и JDBC-драйвером:

# install flyway # cd $(which flyway) // prepare this command for your environment  cd libexec # set actual versions .jar files  cd drivers && curl -L -o ydb-jdbc-driver-shaded-2.1.0.jar https://repo.maven.apache.org/maven2/tech/ydb/jdbc/ydb-jdbc-driver-shaded/2.1.0/ydb-jdbc-driver-shaded-2.1.0.jar  cd ../lib && curl -L -o flyway-ydb-dialect.jar https://repo.maven.apache.org/maven2/tech/ydb/dialects/flyway-ydb-dialect/1.0.0-RC0/flyway-ydb-dialect-1.0.0-RC0.jar

Управление миграциями с помощью Flyway

baseline

Команда baseline инициализирует Flyway в существующей базе данных, исключая все миграции вплоть до baselineVersion включительно.

Предположим, что мы имеем существующий проект с текущей схемой базы данных:

Запишем наши существующие миграции следующим образом (таблицы взяты из примера):

db/migration:   V1__create_series.sql   V2__create_seasons.sql   V3__create_episodes.sql

Установим baselineVersion = 3, затем выполним следующую команду:

flyway -url=jdbc:ydb:grpc://localhost:2136/local -locations=db/migration -baselineVersion=3 baseline

Результатом исполнения будет созданная таблица flyway_schema_history с baseline записью:

Создана baseline запись

Создана baseline запись

migrate

Команда migrate обновляет схему базы данных до последней версии. Если таблица истории схемы не была создана, то Flyway создаст ее автоматически.

Добавим к предыдущему примеру миграцию загрузки данных:

db/migration:   V1__create_series.sql   V2__create_seasons.sql   V3__create_episodes.sql   V4__load_data.sql

Применим последнюю миграцию следующей командой:

flyway -url=jdbc:ydb:grpc://localhost:2136/local -locations=db/migration migrate

Результатом исполнения будет загрузка данных в таблицы series, seasons и episodes:

Результат загрузки данных

Результат загрузки данных

Обновим схему путем добавления вторичного индекса:

db/migration:   V1__create_series.sql   V2__create_seasons.sql   V3__create_episodes.sql   V4__load_data.sql   V5__create_series_title_index.sql

Содержимое файла V5__create_series_title_index.sql:

ALTER TABLE `series` ADD INDEX `title_index` GLOBAL ON (`title`);

Применим последнюю миграцию следующей командой:

flyway -url=jdbc:ydb:grpc://localhost:2136/local -locations=db/migration migrate

Результатом будет появление вторичного индекса у таблицы series:

Cоздан индекс title_index у таблицы series

Cоздан индекс title_index у таблицы series

info

Команда info печатает подробные сведения и информацию о состоянии всех миграций.

Добавим еще одну миграцию, которая переименовывает раннее добавленный вторичный индекс:

db/migration:   V1__create_series.sql   V2__create_seasons.sql   V3__create_episodes.sql   V4__load_data.sql   V5__create_series_title_index.sql   V6__rename_series_title_index.sql

Содержимое файла V6__rename_series_title_index.sql:

ALTER TABLE `series` RENAME INDEX `title_index` TO `title_index_new`;

После исполнения следующей команды:

flyway -url=jdbc:ydb:grpc://localhost:2136/local -locations=db/migration info

Результатом будет подробная информация о состоянии миграций:

+-----------+---------+---------------------------+----------+---------------------+--------------------+----------+ | Category  | Version | Description               | Type     | Installed On        | State              | Undoable | +-----------+---------+---------------------------+----------+---------------------+--------------------+----------+ | Versioned | 1       | create series             | SQL      |                     | Below Baseline     | No       | | Versioned | 2       | create seasons            | SQL      |                     | Below Baseline     | No       | | Versioned | 3       | create episodes           | SQL      |                     | Ignored (Baseline) | No       | |           | 3       | << Flyway Baseline >>     | BASELINE | 2024-04-16 12:09:27 | Baseline           | No       | | Versioned | 4       | load data                 | SQL      | 2024-04-16 12:35:12 | Success            | No       | | Versioned | 5       | create series title index | SQL      | 2024-04-16 12:59:20 | Success            | No       | | Versioned | 6       | rename series title index | SQL      |                     | Pending            | No       | +-----------+---------+---------------------------+----------+---------------------+--------------------+----------+

validate

Команда validate проверяет соответствие примененных миграций к миграциям, которые находятся в файловой системе пользователя.

После применения к текущим миграциям следующей команды:

flyway -url=jdbc:ydb:grpc://localhost:2136/local -locations=db/migration validate

В логах будет написано, что последняя миграция не была применена к нашей базе данных:

ERROR: Validate failed: Migrations have failed validation Detected resolved migration not applied to database: 6. To fix this error, either run migrate, or set -ignoreMigrationPatterns='*:pending'.

Давайте ее применим, выполнив flyway .. migrate. Теперь валидация проходит успешно, вторичный индекс переименован.

Далее изменим файл уже ранее примененной миграции V4__load_date.sql, удалив комментарии в SQL-скрипте.

После исполнения команды валидации, получим закономерную ошибку о том, что checksum различается в измененной миграции:

ERROR: Validate failed: Migrations have failed validation Migration checksum mismatch for migration version 4 -> Applied to database : 591649768 -> Resolved locally    : 1923849782

repair

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

Устраним проблему с разными checksum, выполнив следующую команду:

flyway -url=jdbc:ydb:grpc://localhost:2136/local -locations=db/migration repair

Результатом будет обновление колонки checksum в таблице flyway_schema_history у записи, отвечающей за миграцию V4__load_data.sql:

Обновлено поле checksum

Обновлено поле checksum

После восстановления таблицы лога валидация проходит успешно.

Также с помощью команды repair можно удалить неудавшийся DDL-скрипт.

clean

Команда clean удаляет все таблицы в схеме базы данных.

Так как в отличие от других СУБД YDB не имеет такой сущности, как schema, команда clean удалит все таблицы в вашей базе данных.

Удалим все таблицы в нашей базе данных следующей командой:

flyway -url=jdbc:ydb:grpc://localhost:2136/local -locations=db/migration -cleanDisabled=false clean

Результатом будет пустая база данных:

Пустая база данных

Пустая база данных

Распределенные блокировка в Flyway

При определении новых миграций, которые еще не были применены в базе данных, Flyway берет распределенную блокировку перед их применением.

Здесь нет общепринятого решения, у каждой СУБД свое решение.

В Oracle и Derby:

LOCK TABLE flyway_history_schema IN EXCLUSIVE MODE

В PostgreSQL:

SELECT pg_try_advisory_xact_lock("flyway1")

Для YDB взятие блокировки похоже на подход CockroachDB, Google Spanner или Apache Ignite.

В таблицу истории миграций flyway_schema_history клиент пытается вставить фиктивную запись c ID = -100:

INSERT INTO flyway_schema_history(installed_rank, version, description) VALUES (-100, $tableLockId, 'flyway-lock')

И кто успел вставить такую запись, тот и лидер.

Отпускается такая блокировка следующей SQL-командой:

DELETE FROM flyway_schema_history FROM installed_rank = -100

Важным отличием от CockroachDB и Google Spanner является то, что мы не проставляем тайм-аут истечения блокировки, а приостанавливаем процесс для расследования DBA, как сделано в Apache Ignite. Так как мы не знаем, в какой момент отказал лидер и в каком состоянии наша база данных.

А еще ScheduledThreadPool не закрывается, он нужен для процесса продления такой блокировки.

Поддержка и контакты

Если вы столкнулись с какой-то проблемой или у вас есть идея по улучшению диалекта YDB, то можно открыть issue в репозитории ydb-java-dialects с тегом flyway.

Либо приходите обсудить её в публичный Telegram чат YDB.

Документация по Flyway находится по ссылке.


ссылка на оригинал статьи https://habr.com/ru/articles/815085/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *