MySQL の binlog タイムスタンプと exec_time の関係の詳細な説明

binlog のタイムスタンプと exec_time の関係の詳細な説明。

著者: Li Xichao 氏、江蘇商業銀行 DBA、データベースとミドルウェアの運用、保守、構築を担当。 MySQL、Python、Oracle が得意で、サイクリング、テクノロジーの研究、共有が大好きです。

Aikeson オープンソース コミュニティによって作成されているため、オリジナルのコンテンツを許可なく使用することはできません。転載する場合は編集者に連絡し、出典を明記してください。

この記事は約 2,000 ワードで、読むのに 8 分かかると予想されます。

概要

最近、システムのテストを行ったところ、マスターとスレーブの同期に遅延があることが判明し、binlog により遅延の原因が確認されました。mysqlbinlogコマンドを使用してこれを解析したところ、その情報は「やや曖昧だが理解できない」ことがわかりました。

たとえば、次の 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

上記のバイナリログから、(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操作

さらに (P2):

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

P2 情報に関して、次の質問が行われます。

  • Q1: P2 のフィールドは何を意味しますか?どのように計算されますか?
  • Q2: P2 のフィールドと P1 から見えるタイムスタンプとの間にはどのような関係がありますか?
  • Q4: P1 のタイムスタンプはどのように取得されますか?特にマスタースレーブ環境では

このために、テスト検証とソースコード分析を通じて、exec_time共通のイベント時間とバイナリログの起源が分析され、フィールド間の関係が要約されます。

次の分析は MySQL 8.0 に基づいており、フィールドはバージョンによって異なる場合があります。

マスターノードのbinlogログ

1.GTIDイベント

タイムスタンプ

メインノードの場合: 特別な指示がない場合、Event はtimestamp各スレッドの実行開始位置でdispatch_command()最新のタイムスタンプ()を取得し、 thd->start_timeEvent オブジェクト生成時thd->start_timeに代入しますLog_event::common_header->when

主なスタック情報は次のとおりです。

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

即時コミットタイムスタンプ/オリジナルコミットタイムスタンプ

immediate_commit_timestamp取得されたタイムスタンプは送信時刻であり、マスター ノードはoriginal_commit_timestampに等しいです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.BEGINイベント

タイムスタンプ

注: マスター ノードの BEGIN イベントの場合、timestampこれは BEGIN が実行されたときのタイムスタンプではなく、最初の変更操作のタイムスタンプです。 InnoDB レイヤーのデータの最初の行の変更が完了すると、Table_map イベントが生成され、書き込まれます。 Table_map イベントを生成する前に、この時点でトランザクション全体の binlog キャッシュが空であれば、操作はすぐに取得されthd->start_time、実際の BEGIN イベントが生成されます。

実行時間

同時に、マスターノードの場合は、exec_timeBEGIN Event の生成過程で最新のタイムスタンプ - BEGIN Event を取得することで取得されますtimestamp

実行時間 = A - B

  • A: 最初に変更された SQL を実行し、最初の行変更 (書き込み/更新/削除) 操作が完了した後、BEGIN イベントが生成された時刻です。
  • B: 最初に変更されたSQLの実行開始時刻(thd->start_time)

内部スタックと実行シーケンスは次のとおりです。

3. Table_map イベント

4.書き込みイベント

5.Xidイベント

6. マスターノードの概要

  • BEGIN イベントに加えて、timestampバイナリログに書き込む必要がある最初の操作 (書き込み/更新/削除など) の開始時刻です。
  • 他のイベントの場合は、timestampSQL ステートメントが実行される開始時刻です。
  • immediate_commit_timestamp/original_commit_timestampこれは送信時のタイムスタンプです。
  • 実行時間 = A - B
    • A: 最初に変更された SQL を実行し、最初の行変更 (書き込み/更新/削除) 操作が完了した後、BEGIN イベントが生成された時刻です。
    • B: 最初に変更されたSQLの実行開始時刻(thd->start_time)

スレーブノードのbinlogログ

1.GTIDイベント

タイムスタンプ

スレーブ ノード: GTID イベントの場合、MySQL はイベントの解析時にマスター ノードの GTID/XID イベントのタイムスタンプを取得しないため、トランザクションの前の操作のタイムスタンプを「継承」します。スレーブ ノード上のすべての変更操作のタイムスタンプは、マスター ノードが操作を実行したときのタイムスタンプから取得されます。したがって、スレーブ ノードの GTID/XID イベントの時刻は、マスター ノードの最後の変更操作のタイムスタンプになります。

即時コミットタイムスタンプ/オリジナルコミットタイムスタンプ

immediate_commit_timestampスレーブ ノードの送信時刻のタイムスタンプを取得します。original_commit_timestampGTID Event から取得されますoriginal_commit_timestamp。つまり、メイン ノードが操作を送信しますtimestamp

主なスタック情報は次のとおりです。

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

公式

即時コミットタイムスタンプ - オリジナルコミットタイムスタンプ = A + B + C

  • A =マスターノードがバイナリログをスレーブノードに転送するのにかかる時間
  • B =スレーブ ノードからバイナリログを再生するのにかかる時間
  • C = 同期遅延/中断時間

2.BEGINイベント

タイムスタンプ

これはtimestampメイン ノードの BEGIN イベントからのものですtimestamp。実際に実行するとBEGINイベントが取得されtimestamp、 に代入されますthd->start_time/thd->user_time。ノードから Event オブジェクトを生成するときは、thd->start_timeからタイムスタンプを取得し続けるだけです。

実行時間

その後、スレーブ ノードはexec_time、BEGIN イベントの生成プロセスで最新のタイムスタンプtimestamp(timestampマスター ノードからの変更された SQL の実行開始時刻に注意してください) を取得します。

主なスタック情報は次のとおりです。

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

公式

実行時間 = A + B + C + D

  • A =マスターノード、トランザクション時間全体
  • B = バイナリログ送信時間
  • C = 同期遅延/中断時間 (おそらく - メジャー)
  • D = ノードからのデータ変更の最初の行を完了します

original_commit_timestamp - begin イベントの timestamp = は、マスター ノード上のトランザクション全体 ([メイン優先変更] から [メインコミット開始]) の実際の消費時間を示します。

3. Table_map イベント

4.書き込みイベント

5.Xidイベント

6. ノードセクションから

  • GTID/XID イベントを除き、他のイベントのタイムスタンプはマスター ノードのイベントから取得されます。
  • GTID/XID イベントは、timestampマスター ノードの最後の変更操作の開始時刻です。
  • GTID イベントはoriginal_commit_timestampマスター ノードから取得され、immediate_commit_timestamp最新のタイムスタンプです。
  • 実行時間 = A - B
    • A =ノードから生成された BEGIN イベントの最新のタイムスタンプ
    • B =マスターノードが最初の DML 操作を実行する時間を開始します

結論

この時点で、binlog 内のタイムスタンプと情報はexec_time基本的に整理されています。興味のある方は記事の先頭に戻って、Q1 ~ Q3 への回答があるかどうかを確認してください。

最後に、binlog を使用してマスター/スレーブ同期の問題をより快適に分析できるように、関連フィールドをより深く理解するためにいくつかのケースをシミュレーションすることをお勧めします。

上記の情報は、作者のレベルに限りがありますので、不足がある場合は、お気軽にコメント欄でご連絡ください。

さらに技術的な記事については、https: //opensource.actionsky.com/をご覧ください。

SQLEについて

SQLE は、開発環境から運用環境までの SQL 監査と管理をカバーする包括的な SQL 品質管理プラットフォームです。主流のオープンソース、商用および国内データベースをサポートし、開発、運用および保守のためのプロセス自動化機能を提供し、オンライン効率を向上させ、データ品質を向上させます。

SQL取得

タイプ 住所
リポジトリ https://github.com/actiontech/sqle
書類 https://actiontech.github.io/sqle-docs/
リリースニュース https://github.com/actiontech/sqle/releases
データ監査プラグイン開発ドキュメント https://actiontech.github.io/sqle-docs/docs/dev-manual/plugins/howtouse
未知のオープンソースプロジェクトはどれくらいの収益をもたらすのでしょうか? Microsoftの中国AIチームは数百人を巻き込んでまとめて米国に向かいましたが、 Yu Chengdong氏の転職は 15年間の「恥の柱」に釘付けになったと正式に発表されました。前に、しかし今日、彼は私たちに感謝しなければなりません— Tencent QQ Video は過去の屈辱を晴らしますか? 華中科技大学のオープンソース ミラー サイトが外部アクセス向けに正式にオープン レポート: 開発者の 74% にとって Django が依然として第一候補であるZed エディターは、 有名なオープンソース企業の元従業員 によって開発されました。 ニュースを伝えた: 部下から異議を申し立てられた後、技術リーダーは激怒し無礼になり、女性従業員は解雇され、妊娠した。 Alibaba Cloud が Tongyi Qianwen 2.5 を正式リリース Microsoft が Rust Foundation に 100 万米ドルを寄付
{{名前}}
{{名前}}

おすすめ

転載: my.oschina.net/actiontechoss/blog/11112538