Статьи

Многопоточная репликация с MySQL 5.6: используйте GTID!

Первоначально Написал Стефан Комбоудон

MySQL 5.6 позволяет выполнять реплицированные события параллельно, если данные распределены по нескольким базам данных. Эта функция называется «Многопоточный ведомый» (MTS), и ее легко включить, установив значение slave_parallel_workers> 1. Однако, если вы решите использовать MTS без GTID, у вас могут возникнуть досадные проблемы. Давайте посмотрим на два из них.

Пропуск ошибок репликации

Когда репликация останавливается с ошибкой, частым подходом является «игнорировать сейчас и исправить позже». Это означает, что вы сможете запустить SET GLOBAL sql_slave_skip_counter=1перезапуск репликации как можно быстрее, а затем использовать pt-table-checkum / pt-table-sync для повторной синхронизации данных на ведомом устройстве.

Тогда день, когда я ударил:

mysql> show slave status;
[...]
Last_SQL_Error: Worker 0 failed executing transaction '' at master log mysql-bin.000017, end_log_pos 1216451; Error 'Duplicate entry '1001' for key 'PRIMARY'' on query. Default database: 'db1'. Query: 'INSERT INTO sbtest1 (id, k, c, pad) VALUES (0, 5320, '49123511666-22272014664-85739796464-62261637750-57593947547-00947134109-73607171516-11063345053-55659776318-82888369235', '11400300639-05875856680-20973514928-29618434959-69429576205')'
Exec_Master_Log_Pos: 1005432

Я попытался использовать трюк:

mysql> set global sql_slave_skip_counter=1;
mysql> start slave;

Но:

mysql> show slave status;
[...]
Last_SQL_Error: Worker 0 failed executing transaction '' at master log mysql-bin.000017, end_log_pos 1216451; Error 'Duplicate entry '1001' for key 'PRIMARY'' on query. Default database: 'db1'. Query: 'INSERT INTO sbtest1 (id, k, c, pad) VALUES (0, 5320, '49123511666-22272014664-85739796464-62261637750-57593947547-00947134109-73607171516-11063345053-55659776318-82888369235', '11400300639-05875856680-20973514928-29618434959-69429576205')'
Exec_Master_Log_Pos: 1005882

Обратите внимание, что позиция, указанная в сообщении Exec_Master_Log_Pos, переместилась вперед, но у меня все еще есть ошибка повторяющегося ключа. Что не так?

Проблема в том, что сообщаемые позиции SHOW SLAVE STATUSвводят в заблуждение при использовании МТС. Цитирование документации о Exec_Master_Log_Pos:

При использовании многопоточного ведомого устройства (путем установки для slave_parallel_workers ненулевого значения в MySQL 5.6.3 и более поздних версиях) значение в этом столбце фактически представляет метку «низкого уровня», до которой не остаются незафиксированные транзакции. Поскольку текущая реализация позволяет выполнять транзакции в разных базах данных в другом порядке на ведомом устройстве, это не обязательно позиция самой последней выполненной транзакции.

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

mysql> start slave until sql_after_mts_gaps;

И теперь я могу наконец пропустить ошибку и перезапустить репликацию:

mysql> set global sql_slave_skip_counter=1;
mysql> start slave;
mysql> show slave statusG
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes

Последнее, что нужно сделать, это, конечно, повторно синхронизировать раба.

Резервные копии

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

Например, если вы запустите, mysqldump --dump-slave=2чтобы получить позицию binlog мастера, mysqldumpсначала запустите, STOP SLAVEа затем SHOW SLAVE STATUS. Достаточно ли остановки ведомого, чтобы избежать пробелов в исполнении? На самом деле нет .

Похоже, что единственным вариантом является: запустить, STOP SLAVEа START SLAVE UNTIL SQL_AFTER_MTS_GAPSзатем, mysqldumpпока репликация остановлена. Не очень удобно!

GTIDs на помощь!

Решение обеих проблем заключается в использовании GTID.

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

Они также помогают при резервном копировании, потому что mysqldumpзанимает позицию, с gtid_executedкоторой обновляется при каждой фиксации транзакции (XtraBackup делает это тоже).

Вывод

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

Все ли радует при использовании как GTID, так и MTS? Не совсем … Но это будет тема для отдельного поста!

Кстати, если вы находитесь в районе Брюсселя в эти выходные, приходят ко мне и другие великие ораторы на MySQL и друзей devroom в FOSDEM !