Несколько экземпляров приложения пытаются перенести одну и ту же базу данных одновременно

Я только начал использовать flyway в довольно стандартном веб-приложении Spring 2.5 с базой данных mysql. Он был в производстве в течение многих лет и имеет много данных.

Я подключил его для автоматической миграции при запуске с помощью

<bean id="flyway" class="com.googlecode.flyway.core.Flyway" init-method="migrate">
    <property name="dataSource" ref="dataSource"/>
</bean>

и сделал так, чтобы диспетчер единиц персистентности Spring (с использованием jpa) зависел от него, поэтому база данных будет перенесена до инициализации JPA.

Это прекрасно работает.

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

Мне нравится тестировать эти вещи, прежде чем что-то делать в продакшене, что я и сделал; и что произошло, когда два экземпляра приложения запускались одновременно с длительной миграцией (6 минут), так это то, что через некоторое время второй экземпляр вышел из строя с:

 Caused by: com.googlecode.flyway.core.exception.FlywayException: Unable to lock metadata table 'schema_version' in schema 'dbschema'
    at com.googlecode.flyway.core.metadatatable.MetaDataTable.lock(MetaDataTable.java:148)
    at com.googlecode.flyway.core.migration.DbMigrator$1.doInTransaction(DbMigrator.java:116)
    at com.googlecode.flyway.core.migration.DbMigrator$1.doInTransaction(DbMigrator.java:114)
    at com.googlecode.flyway.core.util.jdbc.TransactionTemplate.execute(TransactionTemplate.java:54)
    at com.googlecode.flyway.core.migration.DbMigrator.migrate(DbMigrator.java:113)
    ...

Глубже в трассировке стека находится SQLException:

Caused by: java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1055)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956)
    ...

По существу, кажется, тайм-аут.

Мы используем mysql и, на самом деле, пытаемся заблокировать таблицу метаданных с помощью

select * from dbschema.schema_version for update

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

mysql> show variables like 'innodb_lock_wait_timeout';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| innodb_lock_wait_timeout | 120   |
+--------------------------+-------+

Который явный виновник. Однако я не уверен, что хочу увеличить сумму, так как я мог бы захотеть, чтобы она истекла, если такое событие произойдет по какой-то другой причине.

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

SET innodb_lock_wait_timeout = 240;
ERROR 1238 (HY000): Variable 'innodb_lock_wait_timeout' is a read only variable

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

У кого-нибудь есть другие предложения?


person kerebus    schedule 10.10.2012    source источник


Ответы (1)


Есть 3 возможности:

person Axel Fontaine    schedule 11.10.2012
comment
Flyway, похоже, блокирует базу данных перед вызовом каких-либо сценариев миграции. Разве невозможно тогда установить тайм-аут ожидания глобальной блокировки во время выполнения, если MetaDataTable#lock() не поддерживает передачу тайм-аута в качестве параметра? Все остальные экземпляры в кластере будут пытаться вызвать metaDataTable#lock(), но всегда будут прерываться по тайм-ауту с глобальной настройкой тайм-аута сервера (50 секунд). - person dukethrash; 01.05.2014