Статьи

Ошибочные транзакции: основное препятствие для аварийного переключения на основе GTID в MySQL 5.6

Эта статья была первоначально написана Stephane Combaudon

Ранее я писал о новом протоколе репликации, который поставляется с GTID в MySQL 5.6. Благодаря этому новому протоколу репликации вы можете непреднамеренно создавать ошибочные транзакции, которые могут превратить любое аварийное переключение в кошмарный сон. Давайте посмотрим на проблемы и возможные решения.

Вкратце

  • Ошибочные транзакции могут вызывать всевозможные ошибки повреждения / репликации данных при сбое.
  • Обнаружение ошибочных транзакций может быть сделано с помощью функций GTID_SUBSET () и GTID_SUBTRACT () .
  • Если вы обнаружили ошибочную транзакцию на одном сервере, передайте пустую транзакцию с GTID ошибочной транзакции на всех других серверах.
  • Если вы используете инструмент для выполнения отработки отказа, убедитесь, что он может обнаружить ошибочные транзакции. На момент написания этой статьи только mysqlfailover и mysqlrpladmin из MySQL Utilities могут это сделать.

Что такое ошибочные транзакции?

Проще говоря, это транзакции, выполняемые непосредственно на подчиненном устройстве. Таким образом, они существуют только на конкретного раба. Это может произойти из-за ошибки (приложение пишет в ведомое устройство вместо записи в ведущее устройство), или это может быть сделано из-за необходимости (вам нужны дополнительные таблицы для отчетов).

Почему они могут создавать проблемы, которых не было до GTID?

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

Сравните то, что происходит в этой установке «главный-подчиненный», сначала с репликацией на основе позиции, а затем с репликацией на основе GTID. А хозяин, Б раб:

# POSITION-BASED REPLICATION
# Creating an errant transaction on B
mysql> create database mydb;
 
# Make B the master, and A the slave
 
# What are the databases on A now?
mysql> show databases like 'mydb';
Empty set (0.01 sec)

Как и ожидалось, база данных mydb не создана на A.

# GTID-BASED REPLICATION
# Creating an errant transaction on B
mysql> create database mydb;
 
# Make B the master, and A the slave
 
# What are the databases on A now?
mysql> show databases like 'mydb';
+-----------------+
| Database (mydb) |
+-----------------+
| mydb            |
+-----------------+

mydb был воссоздан на A из-за нового протокола репликации: когда A подключается к B, они обмениваются собственным набором выполненных GTID, и master (B) отправляет любую отсутствующую транзакцию. Вот это create databaseутверждение.

Как вы можете видеть, основная проблема с ошибочными транзакциями заключается в том, что при сбое вы можете выполнять транзакции «из ниоткуда», которые могут молча испортить ваши данные или нарушить репликацию.

Как их обнаружить?

Если мастер работает, это легко сделать с помощью функции GTID_SUBSET () . Поскольку все записи должны идти к ведущему устройству, GTID, выполняемые на любом ведомом устройстве, всегда должны быть подмножеством GTID, выполняемых на главном устройстве. Например:

# Master
mysql> show master status\G
*************************** 1. row ***************************
             File: mysql-bin.000017
         Position: 376
     Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set: 8e349184-bc14-11e3-8d4c-0800272864ba:1-30,
8e3648e4-bc14-11e3-8d4c-0800272864ba:1-7
 
# Slave
mysql> show slave status\G
[...]
Executed_Gtid_Set: 8e349184-bc14-11e3-8d4c-0800272864ba:1-29,
8e3648e4-bc14-11e3-8d4c-0800272864ba:1-9
 
# Now, let's compare the 2 sets
mysql> > select gtid_subset('8e349184-bc14-11e3-8d4c-0800272864ba:1-29,
8e3648e4-bc14-11e3-8d4c-0800272864ba:1-9','8e349184-bc14-11e3-8d4c-0800272864ba:1-30,
8e3648e4-bc14-11e3-8d4c-0800272864ba:1-7') as slave_is_subset;
+-----------------+
| slave_is_subset |
+-----------------+
|               0 |
+-----------------+

Хм, похоже, что ведомое устройство выполнило больше транзакций, чем ведущее, это указывает на то, что ведомое устройство выполнило как минимум 1 ошибочную транзакцию. Можем ли мы знать GTID этих транзакций? Конечно, давайте использовать GTID_SUBTRACT () :

select gtid_subtract('8e349184-bc14-11e3-8d4c-0800272864ba:1-29,
8e3648e4-bc14-11e3-8d4c-0800272864ba:1-9','8e349184-bc14-11e3-8d4c-0800272864ba:1-30,
8e3648e4-bc14-11e3-8d4c-0800272864ba:1-7') as errant_transactions;
+------------------------------------------+
| errant_transactions                      |
+------------------------------------------+
| 8e3648e4-bc14-11e3-8d4c-0800272864ba:8-9 |
+------------------------------------------+

Это означает, что у ведомого есть 2 ошибочные транзакции.

Теперь, как мы можем проверить ошибочные транзакции, если мастер не работает (например, мастер потерпел крах, и мы хотим переключиться на одного из подчиненных)? В этом случае нам придется выполнить следующие шаги:

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

Некоторые из вас могут задаться вопросом, как узнать, какие транзакции исходят от мастера, так как он недоступен: SHOW SLAVE STATUSдает UUID мастера, который используется в GTID всех транзакций, исходящих от мастера.

Как от них избавиться?

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

Например, если у вас есть 3 сервера, A (ведущий), B (ведомый с ошибочной транзакцией: XXX: 3) и C (ведомый с 2 ​​ошибочными транзакциями: YYY: 18-19), вам придется ввести следующие пустые транзакции в псевдокоде:

# A
- Inject empty trx(XXX:3)
- Inject empty trx(YYY:18)
- Inject empty trx(YYY:19)
 
# B
- Inject empty trx(YYY:18)
- Inject empty trx(YYY:19)
 
# C
- Inject empty trx(XXX:3)

Вывод

Если вы хотите переключиться на репликацию на основе GTID, обязательно проверяйте ошибочные транзакции перед любым запланированным или незапланированным изменением топологии репликации. И будьте особенно осторожны, если вы используете инструмент, который реконфигурирует для вас репликацию: на момент написания только mysqlrpladmin и mysqlfailover из MySQL Utilities могут предупредить вас, если вы пытаетесь выполнить небезопасное изменение топологии.