Explication détaillée de la relation entre l'horodatage du binlog de MySQL et exec_time

Explication détaillée de la relation entre l'horodatage binlog et exec_time.

Auteur : Li Xichao, DBA de la Jiangsu Commercial Bank, responsable de l'exploitation, de la maintenance et de la construction des bases de données et des middlewares. Bon en MySQL, Python, Oracle et aime le cyclisme, la recherche technologique et le partage.

Produit par la communauté open source Aikeson, le contenu original ne peut être utilisé sans autorisation. Veuillez contacter l'éditeur et indiquer la source de réimpression.

Cet article compte environ 2 000 mots et sa lecture devrait prendre 8 minutes.

Aperçu

Récemment, lorsqu'un système a été testé, il a été découvert qu'il y avait un retard dans la synchronisation maître-esclave, et la cause du retard a été confirmée via binlog. Après avoir utilisé la commande mysqlbinlog pour l'analyser, j'ai trouvé que les informations qu'il contenait étaient "un peu vagues mais pas compréhensibles".

Par exemple, pour l'extrait de journal binaire suivant :

# 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

À partir du binlog ci-dessus, nous pouvons savoir (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操作

De plus (P2) :

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

Concernant les informations P2, les questions suivantes sont posées :

  • Q1 : Que signifient les champs de P2 ? Comment est-il calculé ?
  • Q2 : Quelle est la relation entre les champs de P2 et l’horodatage vu par P1 ?
  • Q4 : Comment l'horodatage de P1 est-il obtenu ? Surtout dans un environnement maître-esclave

À cette fin, grâce à la vérification des tests et à l'analyse du code source, exec_timel'origine des heures d'événements communes et du binlog est analysée et la relation entre les champs est résumée.

L'analyse suivante est basée sur MySQL 8.0 et les champs peuvent être différents selon les versions.

Journal binlog du nœud maître

1. Événement GTID

horodatage

Pour le nœud principal : s'il n'y a pas d'instructions spéciales, l'événement doit obtenir le dernier horodatage ( ) timestampà la position initiale de chaque exécution de thread et l'attribuer au moment où l'objet Event est produit .dispatch_command()thd->start_timethd->start_timeLog_event::common_header->when

Les principales informations sur la pile sont les suivantes :

|-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)

immédiat_commit_timestamp/original_commit_timestamp

immediate_commit_timestampL'horodatage obtenu est l'heure de soumission et le nœud maître original_commit_timestampest égal à 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. COMMENCER l'événement

horodatage

Remarque : Pour l'événement BEGIN du nœud maître, timestampil ne s'agit pas de l'horodatage de l'exécution de BEGIN, mais de la première opération de modification. Après avoir terminé la modification de la première ligne de données de la couche InnoDB, l'événement Table_map est généré et écrit. Avant de générer l'événement Table_map, si le cache binlog de toute la transaction est vide à ce moment, l'opération sera obtenue immédiatement thd->start_timeet le véritable événement BEGIN sera généré.

heure_exec

En même temps, pour le nœud maître, exec_timeil est obtenu en obtenant le dernier horodatage - BEGIN Event en cours de génération de BEGIN Event timestamp.

exec_time = A - B

  • R : L'heure à laquelle l'événement BEGIN est généré après l'exécution du premier SQL modifié et la fin de l'opération de modification de la première ligne (écriture/mise à jour/suppression).
  • B : L'heure de début d'exécution du premier SQL modifié (thd->start_time)

La pile interne et la séquence d'exécution sont les suivantes :

3. Événement Table_map

4. Écrire un événement

5. Événement XID

6. Résumé du nœud maître

  • En plus de l'événement BEGIN, timestampc'est l'heure de début de la première opération qui doit être écrite dans le journal binaire (telle que : écriture/mise à jour/suppression) ;
  • Pour les autres événements, timestampil s'agit de l'heure de début à laquelle l'instruction SQL est exécutée ;
  • immediate_commit_timestamp/original_commit_timestampIl s'agit de l'horodatage lors de la soumission ;
  • exec_time = A - B
    • R : L'heure à laquelle l'événement BEGIN est généré après l'exécution du premier SQL modifié et la fin de l'opération de modification de la première ligne (écriture/mise à jour/suppression).
    • B : L'heure de début d'exécution du premier SQL modifié (thd->start_time)

Journal binaire du nœud esclave

1. Événement GTID

horodatage

Sur le nœud esclave : pour l'événement GTID, MySQL n'obtiendra pas l'horodatage de l'événement GTID/XID du nœud maître lors de l'analyse de l'événement, il "héritera donc" de l'horodatage de l'opération précédente de la transaction. Les horodatages de toutes les opérations de modification sur le nœud esclave proviennent de l'horodatage lorsque le nœud maître effectue l'opération. Par conséquent, l’heure de l’événement GTID/XID du nœud esclave est l’horodatage de la dernière opération de modification du nœud maître.

immédiat_commit_timestamp/original_commit_timestamp

immediate_commit_timestampObtenez l'horodatage de l'heure de soumission du nœud esclave. Obtenu original_commit_timestampà partir de GTID Événement original_commit_timestamp,C'est - à - dire que le noeud principal soumet l'opération timestamp.

Les principales informations sur la pile sont les suivantes :

|-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)

officiel

immédiat_commit_timestamp - original_commit_timestamp = A + B + C

  • A = Le temps nécessaire au nœud maître pour transférer le binlog vers le nœud esclave
  • B = Le temps nécessaire pour relire le binlog à partir du nœud esclave
  • C = délai de synchronisation/temps d'interruption

2. COMMENCER l'événement

horodatage

Cela timestampvient de BEGIN Événement du noeud principal timestamp. Lorsqu'il est effectivement exécuté, l'événement BEGIN sera obtenu timestampet attribué à thd->start_time/thd->user_time. Lors de la génération d'un objet Event à partir d'un nœud, continuez simplement à thd->start_timeobtenir l'horodatage de .

heure_exec

Ensuite, le nœud esclave exec_timeobtient toujours le dernier horodatage dans le processus de génération de l'événement BEGIN timestamp(notez que timestampl'heure de début d'exécution du SQL modifié à partir du nœud maître) est obtenue.

Les principales informations sur la pile sont les suivantes :

|-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)
            ...

officiel

exec_time = A + B + C + D

  • A = nœud maître, toute la durée de la transaction
  • B = temps de transmission du binlog
  • C = délai de synchronisation/temps d'interruption (probablement - majeur)
  • D = Compléter la première ligne de modification des données à partir du nœud

original_commit_timestamp - timestamp = of begin événement indique la consommation de temps réelle de l'ensemble de la transaction sur le nœud maître ([Main-first modification] à [Main-commit start]).

3. Événement Table_map

4. Écrire un événement

5. Événement XID

6. Depuis la section nœud

  • À l'exception de l'événement GTID/XID, les horodatages des autres événements proviennent des événements du nœud maître ;
  • L'événement GTID/XID est timestampl'heure de début de la dernière opération de modification du nœud maître ;
  • L'événement GTID original_commit_timestampprovient du nœud maître et immediate_commit_timestampconstitue le dernier horodatage ;
  • exec_time = A - B
    • A = Le dernier horodatage de l'événement BEGIN généré à partir du nœud
    • B = Le nœud maître démarre le temps d'exécution de la première opération DML

Conclusion

À ce stade, les horodatages et les informations du binlog exec_timeont été essentiellement triés. Les amis intéressés peuvent revenir au début de l'article et voir s'il y a des réponses aux Q1-Q3.

Enfin, il est recommandé aux lecteurs de simuler plusieurs cas afin d'avoir une compréhension plus approfondie des domaines concernés, afin d'être plus à l'aise lors de l'utilisation de binlog pour analyser des problèmes de synchronisation maître-esclave.

Les informations ci-dessus sont uniquement destinées à la communication. Le niveau de l'auteur est limité. S'il y a des lacunes, n'hésitez pas à communiquer dans la zone de commentaires.

Pour des articles plus techniques, veuillez visiter : https://opensource.actionsky.com/

À propos de SQLE

SQLE est une plateforme complète de gestion de la qualité SQL qui couvre l'audit et la gestion SQL, du développement aux environnements de production. Il prend en charge les bases de données open source, commerciales et nationales grand public, fournit des capacités d'automatisation des processus pour le développement, l'exploitation et la maintenance, améliore l'efficacité en ligne et améliore la qualité des données.

SQLE obtenir

taper adresse
Dépôt https://github.com/actiontech/sqle
document https://actiontech.github.io/sqle-docs/
publier des nouvelles https://github.com/actiontech/sqle/releases
Documentation de développement du plug-in d'audit des données https://actiontech.github.io/sqle-docs/docs/dev-manual/plugins/howtouse
Combien de revenus un projet open source inconnu peut-il rapporter ? L'équipe chinoise d'IA de Microsoft a fait ses valises et s'est rendue aux États-Unis, impliquant des centaines de personnes. Huawei a officiellement annoncé que les changements d'emploi de Yu Chengdong étaient cloués au « pilier de la honte FFmpeg » 15 ans. il y a, mais aujourd'hui il doit nous remercier—— Tencent QQ Video venge son humiliation passée ? Le site miroir open source de l'Université des sciences et technologies de Huazhong est officiellement ouvert à l'accès externe : Django est toujours le premier choix pour 74 % des développeurs. L'éditeur Zed a progressé dans la prise en charge de Linux. Un ancien employé d'une société open source bien connue . a annoncé la nouvelle : après avoir été interpellé par un subordonné, le responsable technique est devenu furieux et impoli, et a été licencié et enceinte. Une employée d'Alibaba Cloud publie officiellement Tongyi Qianwen 2.5 Microsoft fait un don d'un million de dollars à la Fondation Rust.
{{o.name}}
{{m.nom}}

Je suppose que tu aimes

Origine my.oschina.net/actiontechoss/blog/11112538
conseillé
Classement