read_buffer_size может разрывать репликацию данных

в 16:41, , рубрики: mysql, mysql tricks, переводы, метки:

Перевод свежей статьи Miguel Angel Nieto «read_buffer_size can break your replication».

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

Допустим, у нас есть настройка репликации master-master:

max_allowed_packet = 32M
read_buffer_size = 100M

Для разрыва репликации я собираюсь загрузить 4 миллиона строк с помощью LOAD DATA INFILE:

MasterA (test) > LOAD DATA INFILE '/tmp/data' INTO TABLE t;
Query OK, 4510080 rows affected (26.89 sec)

После некоторого времени, команда SHOW SLAVE STATUS на MasterA даст нам следующий вывод:

Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'log event entry exceeded max_allowed_packet; Increase max_allowed_packet on master;the first event 'mysql-bin.000002' at 74416925, the last event read from './mysql-bin.000004' at 171, the last byte read from './mysql-bin.000004' at 190.'

Очень странно! Мы загрузили данные на MasterA, и теперь имеем там разорванную репликацию и ошибку, связанную с max_allowed_packet. Следующая ступень – это проверка двоичных логов для обоих мастеров:

MasterA:

masterA> mysqlbinlog data/mysql-bin.000004 | grep block_len
#Begin_load_query: file_id: 1 block_len: 33554432
#Append_block: file_id: 1 block_len: 33554432
#Append_block: file_id: 1 block_len: 33554432
#Append_block: file_id: 1 block_len: 4194304
#Append_block: file_id: 1 block_len: 33554432
#Append_block: file_id: 1 block_len: 10420608

Нет ни одного блока больше, чем max_allowed_packet (33554432).

MasterB:

masterB> mysqlbinlog data/mysql-bin.000004 | grep block_len
#Begin_load_query: file_id: 1 block_len: 33555308
#Append_block: file_id: 1 block_len: 33555308
#Append_block: file_id: 1 block_len: 33555308
#Append_block: file_id: 1 block_len: 4191676
#Append_block: file_id: 1 block_len: 33555308
#Append_block: file_id: 1 block_len: 10419732

Заметили разницу? 33555308 больше чем max_allowed_packet (33554432), поэтому Master2 записал некоторые блоки на 876 байт больше, чем безопасное значение. Затем MasterA пытается прочитать двоичный лог с MasterB, и репликация разрывается, поскольку пакеты слишком велики. Нет, replicate_same_server_id при этом не включена.

В чем связь между read_buffer_size и этим багом?

Опять, лучше уж привести пример, чем объяснять на словах. Возьмем новые значения:

max_allowed_packet = 32M
read_buffer_size = 16M

Мы снова запускаем LOAD DATA INFILE, и теперь вывод на обоих серверах будет:

#Begin_load_query: file_id: 1 block_len: 16777216
#Append_block: file_id: 1 block_len: 16777216
#Append_block: file_id: 1 block_len: 16777216
#Append_block: file_id: 1 block_len: 16777216
#Append_block: file_id: 1 block_len: 16777216
#Append_block: file_id: 1 block_len: 16777216
#Append_block: file_id: 1 block_len: 16777216
#Append_block: file_id: 1 block_len: 16777216
#Append_block: file_id: 1 block_len: 14614912

Максимальный размер блоков данных основан на значении read_buffer_size, так что теперь они уж точно никогда не будут больше, чем max_allowed_packet.
Следовательно, стоит запомнить, что если значение read_buffer_size больше max_allowed_packet, то это может стать причиной разрыва репликации во время импорта данных в MySQL. Этот баг есть во всех версия с 5.0.x до последней 5.5.25, и самый простой способ обойти его – не ставить значение read_buffer_size больше, чем max_allowed_packet. Похоже на то, что баг 30435 на самом деле до сих пор не исправлен.

И не забывайте о том, что большие значения для read_buffer_size не увеличивают производительности (об этом можно почитать здесь в оригинале, а здесь — перевод).

Автор: Go4Yachiyo

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js