Статьи

Контрольные суммы репликации в MySQL 5.6

Это сообщение написано Стефаном Комбоудоном в блоге MySQL Performance.

MySQL 5.6 имеет внушительный список улучшений. Среди них контрольные суммы репликации привлекли мое внимание, так как кажется, что многие люди неправильно понимают реальную добавленную стоимость этой новой функции. Я слышал, что люди думают, что с помощью контрольных сумм репликации теперь обеспечивается целостность данных между мастером и его репликами. Как мы увидим, это не так просто.

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

  • пишет выполнено на реплике вместо мастера
  • недетерминированные запросы
  • неправильное использование фильтров репликации
  • откат транзакций, смешивающих транзакционные и нетранзакционные таблицы

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

Будут ли контрольные суммы репликации обнаруживать такие проблемы? К сожалению, нет, они не будут.

При этом упомянутые выше причины не единственные, которые могут нарушить целостность данных. Одна довольно распространенная проблема — повреждение двоичного журнала или журнала ретрансляции. Поможет ли вам контрольная сумма репликации в этом случае? Да, они будут!

Контрольные суммы репликации на репликах

Контрольные суммы на рабах контролируются slave_sql_verify_checksumпеременной. Давайте сначала отключим их:

slave1 [localhost] {msandbox} ((none)) > set global slave_sql_verify_checksum=OFF;
Query OK, 0 rows affected (0,00 sec)

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

slave1 [localhost] {msandbox} ((none)) > stop slave sql_thread;
Query OK, 0 rows affected (0,00 sec)

Теперь давайте напишем что-нибудь о мастере:

master [localhost] {msandbox} ((none)) > create database sakila;
Query OK, 1 row affected (0,00 sec)

и испортил релейный журнал (я поменял сакила на сакилб):

[...]
@^@^@^F^Cstd^D!^@!^@^H^@^L^Asakila^@sakila^@create database sakilb5      Ý

Давайте перезапустим поток SQL и посмотрим, что у нас есть на ведомом устройстве:

slave1 [localhost] {msandbox} ((none)) > start slave sql_thread;
Query OK, 0 rows affected (0,01 sec)

slave1 [localhost] {msandbox} ((none)) > show databases like 'sakil%';
+-------------------+
| Database (sakil%) |
+-------------------+
| sakilb            |
+-------------------+

sakila на главном, sakilb на ведомом: целостность данных нарушена, но SHOW SLAVE STATUSне показывает никаких проблем. Это плохо, но ожидаемо.

Теперь мы включим контрольные суммы репликации на ведомом устройстве:

slave1 [localhost] {msandbox} ((none)) > set global slave_sql_verify_checksum=ON;
Query OK, 0 rows affected (0,00 sec)

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

master [localhost] {msandbox} ((none)) > show global variables like 'binlog_checksum';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| binlog_checksum | CRC32 |
+-----------------+-------+

Мы также хотим отказаться от нашего отредактированного вручную файла журнала ретрансляции (поскольку редактирование такого файла вручную может привести к дальнейшему повреждению):

slave1 [localhost] {msandbox} ((none)) > stop slave;
Query OK, 0 rows affected (0,01 sec)

# Use Relay_Master_Log_File and Exec_Master_Log_Pos from SHOW SLAVE STATUS
slave1 [localhost] {msandbox} ((none)) > change master to master_log_file='mysql-bin.000001', master_log_pos=2690;
Query OK, 0 rows affected (0,06 sec)

slave1 [localhost] {msandbox} ((none)) > start slave;
Query OK, 0 rows affected (0,01 sec)

И после повторения тех же шагов, что и выше (остановка потока sql, создание базы данных sakila2 на главном сервере, повреждение журнала ретрансляции, перезапуск потока sql), у нас теперь есть приятное сообщение об ошибке:

slave1 [localhost] {msandbox} ((none)) > show slave status\G
               [...]
 Slave_IO_Running: Yes
Slave_SQL_Running: No
	       [...]
       Last_Errno: 1594
       Last_Error: Relay log read failure: Could not parse relay log event entry. The possible reasons are: the master's binary log is corrupted (you can check this by running 'mysqlbinlog' on the binary log), the slave's relay log is corrupted (you can check this by running 'mysqlbinlog' on the relay log), a network problem, or a bug in the master's or slave's MySQL code. If you want to check the master's binary log or slave's relay log, you will be able to know their names by issuing 'SHOW SLAVE STATUS' on this slave.

Большой! Теперь нас предупреждают, что что-то пошло не так. Также гораздо проще исправить проблему прямо сейчас (вручную или с помощью pt-table-checkum / pt-table-sync), чем через несколько дней или несколько недель спустя, поскольку единственное несоответствие может легко перерасти в массовое повреждение со временем.

Если сообщение об ошибке выглядит слишком загадочно для вас, вы можете использовать новую --verify-binlog-checksumопцию mysqlbinlog:

# mysqlbinlog --verify-binlog-checksum mysql_sandbox18676-relay-bin.000002
[...]
ERROR: Error in Log_event::read_log_event(): 'Event crc check failed! Most likely there is event corruption.', data_len: 103, event_type: 2
ERROR: Could not read entry at offset 283: Error in log format or read error.
[...]

Контрольные суммы репликации на мастере

Мы можем включить их с помощью следующей команды (по умолчанию они отключены):

master [localhost] {msandbox} ((none)) > set global master_verify_checksum=ON;
Query OK, 0 rows affected (0,00 sec)

Теперь, если у нас есть повреждение в двоичном журнале, мы все еще сможем писать на мастере. Одним из способов показать коррупцию является использование SHOW BINLOG EVENTS:

master [localhost] {msandbox} ((none)) > show binlog events;
ERROR 1220 (HY000): Error when executing command SHOW BINLOG EVENTS: Wrong offset or I/O error

Но на рабах коррупция будет очевидна, так как репликация остановится с ошибкой:

slave1 [localhost] {msandbox} ((none)) > show slave status\G
	       [...]
 Slave_IO_Running: No
Slave_SQL_Running: Yes
	       [...]
    Last_IO_Errno: 1236
    Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'event read from binlog did not pass crc check; the first event 'mysql-bin.000001' at 2793, the last event read from './mysql-bin.000001' at 2793, the last byte read from './mysql-bin.000001' at 2896.'

Вывод

Не следует полагать, что контрольные суммы репликации в MySQL 5.6 обеспечат целостность данных во всех сценариях, но они повышают надежность всего процесса репликации. Это большой шаг вперед, спасибо команде по репликации в Oracle!