Проблемы репликации MySQL после отключения электроэнергии

Проблемы репликации MySQL после отключения электроэнергии

После отключения электроэнергии в нашем центре обработки данных возникли проблемы с подчиненными базами данных MySQL.

Вот что есть в журналах одного из подчиненных устройств:

100118 10:05:56 [Note] Slave I/O thread: connected to master 'repl@db1:3306',  replication started in log 'bin-log.004712' at position 724207814
100118 10:05:56 [ERROR] Error reading packet from server: Client requested master to start replication from impossible position ( server_errno=1236)
100118 10:05:56 [ERROR] Got fatal error 1236: 'Client requested master to start replication from impossible position' from master when reading data from binary log
100118 10:05:56 [Note] Slave I/O thread exiting, read up to log 'bin-log.004712', position 724207814

А консоль показывает немного больше деталей:

mysql> show slave status \G;
*************************** 1. row ***************************
             Slave_IO_State:
                Master_Host: db1
                Master_User: repl
                Master_Port: 3306
              Connect_Retry: 10
            Master_Log_File: bin-log.004712
        Read_Master_Log_Pos: 724207814
             Relay_Log_File: mysqld-relay-bin.000105
              Relay_Log_Pos: 98
      Relay_Master_Log_File: bin-log.004712
           Slave_IO_Running: No
          Slave_SQL_Running: Yes
            Replicate_Do_DB: mmplive1,mmpjcr,fui
        Replicate_Ignore_DB:
         Replicate_Do_Table:
     Replicate_Ignore_Table:
    Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
                 Last_Errno: 0
                 Last_Error:
               Skip_Counter: 0
        Exec_Master_Log_Pos: 724207814
            Relay_Log_Space: 98
            Until_Condition: None
             Until_Log_File:
              Until_Log_Pos: 0
         Master_SSL_Allowed: No
         Master_SSL_CA_File:
         Master_SSL_CA_Path:
            Master_SSL_Cert:
          Master_SSL_Cipher:
             Master_SSL_Key:
      Seconds_Behind_Master: NULL
1 row in set (0.00 sec)

ERROR:
No query specified

Просматривая журналы bin на главном сервере, мы видим:

-rw-rw---- 1 mysql mysql  724200412 Jan 18 09:22 bin-log.004712
-rw-rw---- 1 mysql mysql       1904 Jan 18 09:27 bin-log.index
-rw-rw---- 1 mysql mysql    5046830 Jan 18 11:22 slow-log
-rw-rw---- 1 mysql mysql  198249613 Jan 18 11:24 bin-log.004713
  1. Статус Slave показывает, что Exec_Master_Log_Pos и ​​Read_Master_Log_Pos оба равны 724207814, тогда двоичный журнал bin-log.004712. Насколько я понимаю, это значение является позицией байта в двоичном файле журнала.
  2. Файл bin-log.004712 имеет размер всего 724200412 байт, поэтому подчиненные серверы думают, что они выполнили на 7402 байта больше работы, чем на самом деле было сохранено в файле (который находится на ext3 fs, RAID-10, RHEL5). Отсюда и сообщение об ошибке о невозможной позиции журнала и т. д.

Каков наилучший способ исправить положение рабов?

Варианты, которые я рассматриваю:

  1. Устанавливаем каждый подчиненный узел на позицию 0 в следующем файле bin-log (bin-log.004713) и отпускаем их, но я не уверен, насколько это безопасно и сколько данных может быть потеряно.
  2. Нужно ли мне вместо этого делать полное резервное копирование и восстановление (с предполагаемым связанным с этим простоем из-за блокировок таблиц InnoDB)? Я бы хотел избежать этого, если это возможно.

ОБНОВЛЯТЬ:

Я упустил еще один вариант: отодвинуть каждую выполненную подчиненным устройством позицию немного назад, чтобы оно попыталось повторить уже обработанные им команды из bin-log.004712.

решение1

Я выбрал первый вариант.

Это работало до тех пор, пока подчиненный сервер не начал пытаться делать вставки, которые конфликтовали с первичными ключами. Подчиненный сервер выполнил больше работы, чем сохранил главный bin-log, как упоминалось ранее. Один аспект, который я не ожидал, заключался в том, что подчиненный сервер содержал данные, которых не было в главном сервере; т. е. подчиненный сервер сохранил некоторые транзакции до отключения питания, которое главный серверНЕ ИМЕЛупорствовал.

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

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

  • Изменен файл журнала и положение на подчиненном устройстве.

    CHANGE MASTER MASTER_LOG_FILE='bin-log.004713', MASTER_LOG_POS=0; -- on serverB
    
  • Перезапустил подчиненную репликацию на пассивном главном сервере (serverB) до тех пор, пока она не вышла из строя из-за нарушений ограничений первичного ключа, как и в случае с другими подчиненными серверами.

     START SLAVE; -- on serverB
    
  • Остановлена ​​репликация подчиненного сервера с пассивного главного сервера (serverB) на активный главный сервер (serverA).

    STOP SLAVE; -- on serverA
    
  • УДАЛИТЕ строки на подчиненном сервере (serverB), которых не было на главном сервере serverA.

    DELETE FROM SOME_TABLE WHERE ID IN (???,????); -- on serverB
    SHOW MASTER STATUS\G; -- get the new master log position on serverB
    
  • Переместите позицию ведомого exec активного главного сервера (сервера A), чтобы пропустить удаления с пассивного главного сервера (сервера B).

    CHANGE MASTER TO MASTER_LOG_POS=???; --on serverA; use the value just obtained from serverB
    
  • Перезапустите репликацию на активном главном сервере (serverA) и пассивном главном сервере.

    START SLAVE; -- on both machines. serverA does nothing and serverB starts catching up.
    

решение2

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

Связанный контент