Explicação detalhada da relação entre o timestamp do log binário do MySQL e exec_time

Explicação detalhada da relação entre timestamp do log binário e exec_time.

Autor: Li Xichao, DBA do Jiangsu Commercial Bank, responsável pela operação, manutenção e construção de banco de dados e middleware. Bom em MySQL, Python, Oracle e adora ciclismo, pesquisa e compartilhamento de tecnologia.

Produzido pela comunidade de código aberto Aikeson, o conteúdo original não pode ser utilizado sem autorização. Entre em contato com o editor e indique a fonte para reimpressão.

Este artigo tem cerca de 2.000 palavras e espera-se que leve 8 minutos para ser lido.

Visão geral

Recentemente, quando um sistema foi testado, descobriu-se que havia um atraso na sincronização mestre-escravo, e a causa do atraso foi confirmada através do binlog. Depois de usar o comando mysqlbinlog para analisá-lo, descobri que as informações nele contidas eram "um tanto vagas, mas não compreensíveis".

Por exemplo, para o seguinte trecho de binlog:

# at 449880
#240430 18:38:49 server id 345  end_log_pos 449967 CRC32 0xb3e8a02a     GTID    last_committed=13       sequence_number=14      rbr_only=yes    original_committed_timestamp=1714473533138376   immediate_commit_timestamp=1714473539246294     transaction_length=446792
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
# original_commit_timestamp=1714473533138376 (2024-04-30 18:38:53.138376 CST)
# immediate_commit_timestamp=1714473539246294 (2024-04-30 18:38:59.246294 CST)
/*!80001 SET @@session.original_commit_timestamp=1714473533138376*//*!*/;
/*!80014 SET @@session.original_server_version=80027*//*!*/;
/*!80014 SET @@session.immediate_server_version=80027*//*!*/;
SET @@SESSION.GTID_NEXT= 'c0ac4587-6046-11ee-9fa7-001c42c92a7b:44'/*!*/;
# at 449967
#240430 18:38:16 server id 345  end_log_pos 450039 CRC32 0x0c7cb74e     Query   thread_id=16    exec_time=37    error_code=0
SET TIMESTAMP=1714473496/*!*/;
BEGIN
/*!*/;
/*!*/;
# at 450039
#240430 18:38:16 server id 345  end_log_pos 450098 CRC32 0xf9a84808     Table_map: `testdb`.`tb3` mapped to number 110
# at 450098
#240430 18:38:16 server id 345  end_log_pos 458309 CRC32 0xad84e9b0     Write_rows: table id 110
...
# at 896439
#240430 18:38:46 server id 345  end_log_pos 896498 CRC32 0x5cd7cd3b     Table_map: `testdb`.`tb3` mapped to number 110
# at 896498
#240430 18:38:46 server id 345  end_log_pos 896540 CRC32 0x21b77031     Write_rows: table id 110 flags: STMT_END_F
...
### INSERT INTO `testdb`.`tb3`
### SET
###   @1=131060 /* INT meta=0 nullable=0 is_null=0 */
###   @2='c' /* VARSTRING(80) meta=80 nullable=1 is_null=0 */
# at 896540
#240430 18:38:49 server id 345  end_log_pos 896599 CRC32 0x6d6bf911     Table_map: `testdb`.`tb3` mapped to number 110
# at 896599
#240430 18:38:49 server id 345  end_log_pos 896641 CRC32 0xccd2fbb1     Write_rows: table id 110 flags: STMT_END_F
...
### INSERT INTO `testdb`.`tb3`
### SET
###   @1=131061 /* INT meta=0 nullable=0 is_null=0 */
###   @2='c' /* VARSTRING(80) meta=80 nullable=1 is_null=0 */
# at 896641
#240430 18:38:49 server id 345  end_log_pos 896672 CRC32 0xadb14b9d     Xid = 85

Do binlog acima, podemos saber (P1):

#240430 18:38:16 执行 begin 开启了事务  (为便于表述,将时间字段名为timestamp)
#240430 18:38:16 执行了 tb3的insert 操作
#240430 18:38:46 执行了 tb3的insert 操作
#240430 18:38:49 执行了 tb3的insert 操作
#240430 18:38:49 执行了commit操作

Além disso (P2):

original_commit_timestamp=2024-04-30 18:38:53
immediate_commit_timestamp=2024-04-30 18:38:59
exec_time=37

Em relação às informações P2, são feitas as seguintes perguntas:

  • Q1: O que significam os campos em P2? Como é calculado?
  • Q2: Qual é a relação entre os campos de P2 e o carimbo de data/hora visto por P1?
  • Q4: Como é obtido o carimbo de data/hora em P1? Especialmente em um ambiente mestre-escravo

Para tanto, por meio de verificação de testes e análise de código-fonte, exec_timeanalisa-se a origem dos tempos de eventos comuns e no log binário, e resumi-se o relacionamento entre os campos.

A análise a seguir é baseada no MySQL 8.0 e os campos podem ser diferentes em versões diferentes.

Log binário do nó mestre

1. Evento GTID

carimbo de data/hora

Para o nó principal: Se não houver instruções especiais, o Evento deve obter o carimbo de data / hora mais recente ( ) timestampna posição inicial de cada execução do thread e atribuí-lo quando o objeto Event for produzido .dispatch_command()thd->start_timethd->start_timeLog_event::common_header->when

As informações da pilha principal são as seguintes:

|-handle_connection (./sql/conn_handler/connection_handler_per_thread.cc:302)
  |-do_command (./sql/sql_parse.cc:1343)
    |-dispatch_command (./sql/sql_parse.cc:1922)
      // 设置 thd->start_time
      |-thd->set_time()
        |-my_micro_time_to_timeval(start_utime, &start_time)
      |-dispatch_sql_command (./sql/sql_parse.cc:5135)
        |-mysql_execute_command (./sql/sql_parse.cc:3518)
          |-Sql_cmd_dml::execute (./sql/sql_select.cc:579)
          ……
                        |-Table_map_log_event the_event(this, table, table->s->table_map_id,is_transactional)
                        ……
                          |-Rows_log_event *const ev = new RowsEventT(this, table, table->s->table_map_id, )
                          ……
                  |-Xid_log_event end_evt(thd, xid)

imediato_commit_timestamp/original_commit_timestamp

immediate_commit_timestampO carimbo de data/hora obtido é o horário de envio e o nó mestre original_commit_timestampé igual a immediate_commit_timestamp.

|-error = trx_cache.flush(thd, &trx_bytes, wrote_xid)
  |-Transaction_ctx *trn_ctx = thd->get_transaction()
  |-trn_ctx->sequence_number = mysql_bin_log.m_dependency_tracker.step()
  |-if (trn_ctx->last_committed == SEQ_UNINIT): trn_ctx->last_committed = trn_ctx->sequence_number - 1
  |-if (!error): if ((error = mysql_bin_log.write_transaction(thd, this, &writer)))
    |-int64 sequence_number, last_committed
|-m_dependency_tracker.get_dependency(thd, sequence_number, last_committed)
|-thd->get_transaction()->last_committed = SEQ_UNINIT
    |-ulonglong immediate_commit_timestamp = my_micro_time()
    //|-ulonglong original_commit_timestamp = thd->variables.original_commit_timestamp
    |-ulonglong original_commit_timestamp = immediate_commit_timestamp
    |-uint32_t trx_immediate_server_version = do_server_version_int(::server_version)
    |-Gtid_log_event gtid_event(thd, cache_data->is_trx_cache(), last_committed, sequence_number,
        cache_data->may_have_sbr_stmts(), original_commit_timestamp,
        immediate_commit_timestamp, trx_original_server_version,
        trx_immediate_server_version)

2. COMEÇAR Evento

carimbo de data/hora

Nota: Para o evento BEGIN do nó mestre, timestampnão é o carimbo de data/hora quando BEGIN é executado, mas a primeira operação de modificação. Após concluir a modificação da primeira linha de dados na camada InnoDB, o evento Table_map é gerado e gravado. Antes de gerar o evento Table_map, se o cache binlog de toda a transação estiver vazio neste momento, a operação será obtida imediatamente thd->start_timee o evento BEGIN real será gerado.

hora_executiva

Ao mesmo tempo, para o nó mestre, exec_timeé obtido obtendo o último timestamp - Evento BEGIN no processo de geração do Evento BEGIN timestamp.

tempo_exec = A - B

  • R: O momento em que o evento BEGIN é gerado após a execução do primeiro SQL modificado e a conclusão da operação de modificação da primeira linha (gravação/atualização/exclusão).
  • B: O tempo de execução inicial do primeiro SQL modificado (thd->start_time)

A pilha interna e a sequência de execução são as seguintes:

3. Evento Table_map

4. Escreva o evento

5. Evento XID

6. Resumo do nó mestre

  • Além do evento BEGIN, timestampé o horário de início da primeira operação que precisa ser gravada no binlog (como: escrever/atualizar/excluir);
  • Para outros Eventos, timestampé a hora de início em que a instrução SQL é executada;
  • immediate_commit_timestamp/original_commit_timestampEsse é o carimbo de data/hora quando enviado;
  • tempo_exec = A - B
    • R: O momento em que o evento BEGIN é gerado após a execução do primeiro SQL modificado e a conclusão da operação de modificação da primeira linha (gravação/atualização/exclusão).
    • B: O tempo de execução inicial do primeiro SQL modificado (thd->start_time)

Log binário do nó escravo

1. Evento GTID

carimbo de data/hora

No nó escravo: Para Evento GTID, o MySQL não obterá o carimbo de data e hora do Evento GTID/XID do nó mestre ao analisar o evento, portanto, "herdará" o carimbo de data e hora da operação anterior da transação. Os carimbos de data/hora de todas as operações de modificação no nó escravo vêm do carimbo de data/hora quando o nó mestre executa a operação. Portanto, o horário do Evento GTID/XID do nó escravo é o carimbo de data/hora da última operação de modificação do nó mestre.

imediato_commit_timestamp/original_commit_timestamp

immediate_commit_timestampObtenha o carimbo de data/hora do horário de envio do nó escravo. Obtido original_commit_timestampdo evento GTID original_commit_timestamp, ou seja, o nó principal envia a operação timestamp.

As informações da pilha principal são as seguintes:

|-handle_slave_worker (./sql/rpl_replica.cc:5891)
  |-slave_worker_exec_job_group (./sql/rpl_rli_pdb.cc:2549)
    |-Slave_worker::slave_worker_exec_event (./sql/rpl_rli_pdb.cc:1760)
      |-Xid_apply_log_event::do_apply_event_worker (./sql/log_event.cc:6179)
        |-Xid_log_event::do_commit (./sql/log_event.cc:6084)
          |-trans_commit (./sql/transaction.cc:246)
            |-ha_commit_trans (./sql/handler.cc:1765)
              |-MYSQL_BIN_LOG::commit (./sql/binlog.cc:8170)
                |-MYSQL_BIN_LOG::ordered_commit (./sql/binlog.cc:8789)
                  |-MYSQL_BIN_LOG::process_flush_stage_queue (./sql/binlog.cc:8326)
                    |-MYSQL_BIN_LOG::flush_thread_caches (./sql/binlog.cc:8218)
                      |-binlog_cache_mngr::flush (./sql/binlog.cc:1099)
                        |-binlog_cache_data::flush (./sql/binlog.cc:2098)
                          |-MYSQL_BIN_LOG::write_transaction (./sql/binlog.cc:1586)
                            // 生成并写入 GTID event
                            |-ulonglong immediate_commit_timestamp = my_micro_time()
                            |-if (original_commit_timestamp == UNDEFINED_COMMIT_TIMESTAMP){...}
                            |-Gtid_log_event gtid_event(thd, cache_data->is_trx_cache(), last_committed, sequence_number,
                               cache_data->may_have_sbr_stmts(), original_commit_timestamp, immediate_commit_timestamp, trx_original_server_version,
                               trx_immediate_server_version)

oficial

imediato_commit_timestamp - original_commit_timestamp = A + B + C

  • A = O tempo que leva para o nó mestre transferir o log binário para o nó escravo
  • B = O tempo que leva para reproduzir o log binário do nó escravo
  • C = tempo de atraso/interrupção de sincronização

2. COMEÇAR Evento

carimbo de data/hora

Aqui timestampvem o evento BEGIN do nó principal timestamp. Quando for realmente executado, o Evento BEGIN será obtido timestampe atribuído a thd->start_time/thd->user_time. Ao gerar um objeto Event a partir de um nó, continue thd->start_timeobtendo o carimbo de data/hora de .

hora_executiva

Então, o nó escravo exec_timeainda obtém o carimbo de data/hora mais recente no processo de geração do Evento BEGIN timestamp(observe que timestampo tempo de execução inicial do SQL modificado do nó mestre) é obtido.

As informações da pilha principal são as seguintes:

|-handle_slave_worker (./sql/rpl_replica.cc:5891)
  |-slave_worker_exec_job_group (./sql/rpl_rli_pdb.cc:2549)
    |-Slave_worker::slave_worker_exec_event (./sql/rpl_rli_pdb.cc:1760)
      |-Log_event::do_apply_event_worker (./sql/log_event.cc:1083)
        |-Query_log_event::do_apply_event (./sql/log_event.cc:4443)
          |-Query_log_event::do_apply_event (./sql/log_event.cc:4606)
            // 设置 user_time=start_time=ev.common_header->when
            |-thd->set_time(&(common_header->when))
            // query_arg="BEGIN"
            |-thd->set_query(query_arg, q_len_arg)
            ...

oficial

tempo_exec = A + B + C + D

  • A = nó mestre, todo o tempo da transação
  • B = tempo de transmissão do log binário
  • C = tempo de atraso/interrupção de sincronização (provavelmente - maior)
  • D = Conclua a primeira linha de modificação de dados do nó

original_commit_timestamp - timestamp = do evento de início indica o consumo de tempo real de toda a transação no nó mestre ([primeira modificação principal] para [início de confirmação principal]).

3. Evento Table_map

4. Escreva o evento

5. Evento XID

6. Da seção do nó

  • Exceto para Evento GTID/XID, os carimbos de data/hora de outros eventos vêm dos eventos do nó mestre;
  • O evento GTID/XID é timestampo horário de início da última operação de modificação do nó mestre;
  • O evento GTID original_commit_timestampvem do nó mestre e immediate_commit_timestampé o carimbo de data/hora mais recente;
  • tempo_exec = A - B
    • A = O carimbo de data/hora mais recente do evento BEGIN gerado a partir do nó
    • B = O nó mestre inicia o tempo para executar a primeira operação DML

Conclusão

Neste ponto, os carimbos de data e hora no binlog exec_timeforam basicamente resolvidos. Amigos interessados ​​​​podem voltar ao início do artigo e ver se há respostas para Q1-Q3.

Por fim, recomenda-se que os leitores simulem vários casos para ter um entendimento mais profundo dos campos relevantes, para que possam se sentir mais confortáveis ​​ao usar o binlog para analisar problemas de sincronização mestre-escravo.

As informações acima são apenas para comunicação. O nível do autor é limitado. Se houver alguma deficiência, sinta-se à vontade para comunicar na área de comentários.

Para mais artigos técnicos, visite: https://opensource.actionsky.com/

Sobre SQLE

SQLE é uma plataforma abrangente de gerenciamento de qualidade de SQL que cobre auditoria e gerenciamento de SQL desde o desenvolvimento até ambientes de produção. Ele oferece suporte aos principais bancos de dados de código aberto, comerciais e domésticos, fornece recursos de automação de processos para desenvolvimento, operação e manutenção, melhora a eficiência online e melhora a qualidade dos dados.

Obter SQLE

tipo endereço
Repositório https://github.com/actiontech/sqle
documento https://actiontech.github.io/sqle-docs/
lançar notícias https://github.com/actiontech/sqle/releases
Documentação de desenvolvimento de plug-in de auditoria de dados https://actiontech.github.io/sqle-docs/docs/dev-manual/plugins/howtouse
Quanta receita um projeto de código aberto desconhecido pode trazer? A equipe chinesa de IA da Microsoft fez as malas e foi para os Estados Unidos, envolvendo centenas de pessoas. A Huawei anunciou oficialmente que as mudanças de emprego de Yu Chengdong foram fixadas no "Pilar da Vergonha FFmpeg" por 15 anos. atrás, mas hoje ele tem que nos agradecer—— Tencent QQ Video vinga sua humilhação passada? O site espelho de código aberto da Universidade de Ciência e Tecnologia de Huazhong está oficialmente aberto para acesso externo : Django ainda é a primeira escolha para 74% dos desenvolvedores. O editor Zed fez progressos no suporte ao Linux. deu a notícia: Depois de ser desafiado por um subordinado, o líder técnico ficou furioso e rude, foi demitido e engravidou. Funcionária Alibaba Cloud lança oficialmente Tongyi Qianwen 2.5 Microsoft doa US$ 1 milhão para a Rust Foundation.
{{o.nome}}
{{m.nome}}

Acho que você gosta

Origin my.oschina.net/actiontechoss/blog/11112538
Recomendado
Clasificación