MySQL Slave preso em uma posição de registro de bin + log bin único por mais de 17 horas

2

tl; dr: A replicação está parada em um log binário e uma posição específicos, e não sei por que

Eu tenho uma configuração de replicação do MySQL com o MySQL 5.5.

Esta configuração de replicação não tem histórico de ficar para trás e sempre foi sólida.

Esta manhã, notei que o escravo estava atrás do mestre por 17 horas.

Fazendo mais pesquisas, parece ser um problema com o SQL_Thread.

O arquivo de registro principal atual, de acordo com o escravo (via SLAVE STATUS ), é mysql-bin.001306 @ position 20520499 . Isso está de acordo com a saída MASTER STATUS do mestre.

No entanto, SLAVE STATUS mostra que a Relay_Master_Log_File está atualmente em mysql-bin.001302 com Exec_Master_Log_Pos de 36573336 . O Relay_Master_Log_File nem Exec_Master_Log_Pos avançou enquanto eu os monitorava esta manhã.

Examinando os binlogs no master, esta é a instrução localizada em mysql-bin.001302@3657336 :

# at 36573053
#170221 14:33:48 server id 1  end_log_pos 36573130      Query   thread_id=96205677      exec_time=0     error_code=0
SET TIMESTAMP=1487716428/*!*/;
BEGIN
/*!*/;
# at 36573130
# at 36573213
#170221 14:33:48 server id 1  end_log_pos 36573213      Table_map: 'database-name'.'table-name' mapped to number 5873
#170221 14:33:48 server id 1  end_log_pos 36573309      Write_rows: table id 5873 flags: STMT_END_F
### INSERT INTO 'database-name'.'table-name'
### SET
###   @1='xxxxxxxx'
###   @2=6920826
###   @3='xxxxxxxx'
###   @4='GET'
###   @5='address'
###   @6=2017-02-21 14:40:24
###   @7=2017-02-21 14:40:24
# at 36573309
#170221 14:33:48 server id 1  end_log_pos 36573336      Xid = 1668637037
COMMIT/*!*/;
# at 36573336

Por esta altura, ontem, executei algumas grandes consultas para migrar dados para uma nova tabela. O processo parecia um pouco assim:

mysql> insert into tmp_table ( select <rows> from origin table ); -- 44 million rows
mysql> insert into dest_table ( select * from tmp_table ); -- 44 million rows

As duas tabelas em questão não têm uma chave primária ou única nelas, o que eu li poderia ter sido um problema. No entanto, embora a tabela de banco de dados + mostrada na entrada do log binário acima seja a tabela de destino aqui, o registro de inserção mostrado não é aquele gerado durante a migração.

Se você chegou até aqui, você merece pontos de internet.

Neste ponto, não sei mais o que considerar ou onde procurar a razão do log stall. Qualquer insight é apreciado.

Obrigado.

Para referência, aqui está a saída MASTER STATUS e SLAVE STATUS no momento desta postagem:

STATUS MASTER

mysql> show master status;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.001306 | 20520499 |              |                  |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)

STATUS DO ESCRAVO

mysql> show slave status \G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: master-host
                  Master_User: replication-user
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.001306
          Read_Master_Log_Pos: 20520499
               Relay_Log_File: relay-bin.002601
                Relay_Log_Pos: 36573482
        Relay_Master_Log_File: mysql-bin.001302
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB:
          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: 36573336
              Relay_Log_Space: 3565987462
              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: 63435
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Master_Server_Id: 1
1 row in set (0.00 sec)
    
por Jim Rubenstein 22.02.2017 / 17:17

1 resposta

4

Eu estava no caminho certo aqui com as grandes transações de consultas de ontem.

Depois de migrar os dados, executei uma instrução DELETE na tabela original para me livrar das linhas que eu havia migrado.

Essas tabelas são repletas de dados de rastreamento e, portanto, não possuem chaves primárias ou exclusivas.

Devido a como funciona a replicação baseada em ROW, o escravo, em vez de executar a instrução DELETE idêntica que foi executada no master, executa uma instrução DELETE para cada linha, que acaba parecendo assim:

DELETE FROM table WHERE colA=foo AND colB=bar AND colC=baz....etc

E, como não há um índice que corresponda a essa consulta, o encadeamento SQL de replicação encadeada única executou 40 milhões + instruções de exclusão (ou ... estava tentando), o que levou muito tempo para ser executado devido a toda a varredura tinha que ser feito para identificar cada linha (a tabela tinha cerca de 80 milhões de linhas de tamanho na época).

No final, lidei com isso interrompendo o encadeamento escravo ( STOP SLAVE ) ignorando uma única transação escrava ( SET GLOBAL sql_slave_skip_counter = 1; ) e reiniciando o encadeamento secundário ( START SLAVE ).

Isso resultou em meu Master e Slave estarem fora de sincronia na tabela em questão aqui - mas consegui aproveitar a natureza da replicação baseada em linha para trazê-la de volta em sincronia, executando o seguinte no Master:

mysql> CREATE TABLE table_tmp; -- with the same schema as 'table' (SHOW CREATE TABLE table;)
mysql> RENAME TABLE table TO table_bak, table_tmp TO table;
mysql> INSERT INTO table ( SELECT * FROM table_bak );
mysql> DROP TABLE table_bak;

Como o DELETE foi executado no Master, o INSERT aqui só inseriu os registros que eu queria manter (os excluídos foram eliminados). E, como a replicação baseada em linha insere cada linha individualmente, em vez de executar a mesma instrução INSERT INTO ... SELECT, a tabela Slave foi preenchida apenas com os dados desejados. Em seguida, a instrução DROP TABLE subseqüente elimina a tabela no escravo sem precisar endereçar cada linha individualmente.

A ressalva aqui é que, porque a versão Master da tabela ainda estava entre 30 e 40 milhões de linhas ... o INSERT e a replicação consequente acabam bloqueando seu escravo por um tempo (duplicando o problema acima), mas é um muito mais curto (acabou sendo cerca de 20 minutos) devido ao mysql não ter que varrer o banco de dados para as linhas a serem deletadas.

Espero que isso possa ajudar alguém no futuro. Desculpem-se, espero que tenha sido informativo e útil.

    
por 22.02.2017 / 22:05