MySQL의 binlog 타임스탬프와 exec_time 간의 관계에 대한 자세한 설명

binlog 타임스탬프와 exec_time 간의 관계에 대한 자세한 설명입니다.

저자: 데이터베이스 및 미들웨어 운영, 유지 관리 및 구축을 담당하는 Jiangsu Commercial Bank의 DBA Li Xichao. 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

위의 binlog에서 우리는 (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공통 Event 시간과 binlog의 출처를 분석하고, 필드 간의 관계를 정리한다.

다음 분석은 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획득한 타임스탬프는 제출 시간이며 마스터 노드 original_commit_timestampimmediate_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 이벤트의 경우 timestampBEGIN이 실행된 타임스탬프가 아니라 첫 번째 수정 작업입니다. InnoDB 계층의 첫 번째 데이터 행 수정이 완료되면 Table_map 이벤트가 생성되어 기록됩니다. Table_map 이벤트를 생성하기 전 이때 전체 트랜잭션의 binlog 캐시가 비어 있으면 즉시 연산을 획득하여 thd->start_time실제 BEGIN 이벤트가 생성된다.

exec_time

동시에 마스터 노드의 경우 exec_timeBEGIN Event 생성 과정에서 최신 타임스탬프인 BEGIN Event를 획득하여 획득합니다 timestamp.

exec_time = A - B

  • A: 첫 번째 수정 SQL을 실행하고 첫 번째 행 수정(쓰기/업데이트/삭제) 작업을 완료한 후 BEGIN Event가 생성되는 시간입니다.
  • B: 처음 수정된 SQL의 실행 시작 시간 (thd->start_time)

내부 스택과 실행 순서는 다음과 같습니다.

3. Table_map 이벤트

4. 이벤트 작성

5. 시드 이벤트

6. 마스터노드 개요

  • BEGIN 이벤트 외에도 timestampbinlog에 기록해야 하는 첫 번째 작업(예: 쓰기/업데이트/삭제)의 시작 시간입니다.
  • 다른 이벤트 의 경우 timestampSQL 문이 실행되는 시작 시간입니다.
  • immediate_commit_timestamp/original_commit_timestamp이는 제출된 타임스탬프입니다.
  • exec_time = A - B
    • A: 첫 번째 수정 SQL을 실행하고 첫 번째 행 수정(쓰기/업데이트/삭제) 작업을 완료한 후 BEGIN Event가 생성되는 시간입니다.
    • B: 처음 수정된 SQL의 실행 시작 시간 (thd->start_time)

슬레이브 노드 binlog 로그

1. GTID 이벤트

타임스탬프

슬레이브 노드에서: GTID 이벤트의 경우 MySQL은 이벤트를 구문 분석할 때 마스터 노드의 GTID/XID 이벤트 타임스탬프를 얻지 않으므로 이전 트랜잭션 작업의 타임스탬프를 "상속"합니다. 슬레이브 노드의 모든 수정 작업의 타임스탬프는 마스터 노드가 작업을 수행할 때의 타임스탬프에서 나옵니다. 따라서 슬레이브 노드의 GTID/XID 이벤트 시간은 마스터 노드의 마지막 수정 작업의 타임스탬프입니다.

Immediate_commit_timestamp/original_commit_timestamp

immediate_commit_timestamp슬레이브 노드의 제출 시간에 대한 타임스탬프를 가져옵니다. original_commit_timestampGTID 이벤트에서 얻습니다 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)

공식

Immediate_commit_timestamp - 원본_commit_timestamp = A + B + C

  • A = 마스터 노드가 binlog를 슬레이브 노드 로 전송하는 데 걸리는 시간
  • B = 슬레이브 노드에서 binlog를 재생하는 데 걸리는 시간
  • C = 동기화 지연/중단 시간

2. BEGIN 이벤트

타임스탬프

다음은 timestamp메인 노드의 BEGIN 이벤트에서 가져온 것입니다 timestamp. 실제로 실행되면 BEGIN Event를 획득하여 timestamp에 할당 하게 됩니다 thd->start_time/thd->user_time. 노드에서 Event 객체를 생성할 때 계속해서 thd->start_time에서 타임스탬프를 가져옵니다.

exec_time

그런 다음 슬레이브 노드는 exec_timeBEGIN 이벤트를 생성하는 과정에서 여전히 최신 타임스탬프를 얻습니다 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)
            ...

공식

exec_time = A + B + C + D

  • A = 마스터 노드, 전체 거래 시간
  • B = binlog 전송 시간
  • C = 동기화 지연/중단 시간(아마도 - 주요)
  • D = 노드에서 데이터 수정의 첫 번째 행을 완료합니다.

origin_commit_timestamp - timestamp = 시작 이벤트의 시간은 마스터 노드에서 전체 트랜잭션의 실제 시간 소비를 나타냅니다([Main-first 수정]에서 [Main-commit 시작]으로).

3. Table_map 이벤트

4. 이벤트 작성

5. 시드 이벤트

6. 노드 섹션에서

  • GTID/XID 이벤트를 제외하고 다른 이벤트의 타임스탬프는 마스터 노드의 이벤트에서 가져옵니다.
  • GTID/XID 이벤트는 timestamp마스터 노드의 마지막 수정 작업이 시작된 시간입니다.
  • GTID 이벤트는 original_commit_timestamp마스터 노드에서 발생하며 immediate_commit_timestamp최신 타임스탬프입니다.
  • exec_time = A - B
    • A = 노드에서 생성된 BEGIN 이벤트의 최신 타임스탬프
    • B = 마스터 노드가 첫 번째 DML 작업을 실행하는 시간을 시작합니다.

결론

이제 binlog의 타임스탬프와 정보는 exec_time기본적으로 정리되었습니다. 관심 있는 친구는 기사의 시작 부분으로 돌아가서 Q1-Q3에 대한 답변이 있는지 확인할 수 있습니다.

마지막으로, 독자들이 관련 분야에 대한 더 깊은 이해를 갖기 위해 여러 사례를 시뮬레이션하는 것이 좋습니다. 그러면 binlog를 사용하여 마스터-슬레이브 동기화 문제를 분석할 때 더 편안해질 수 있습니다.

위 정보는 작성자의 수준에 제한이 있으니, 부족한 부분이 있으면 댓글로 편하게 소통해주세요.

더 많은 기술 기사를 보려면 https://opensource.actionsky.com/을 방문하세요.

SQLE 소개

SQLE는 개발부터 프로덕션 환경까지 SQL 감사 및 관리를 포괄하는 포괄적인 SQL 품질 관리 플랫폼입니다. 주류 오픈소스, 상용 및 국내 데이터베이스를 지원하고 개발, 운영 및 유지 관리를 위한 프로세스 자동화 기능을 제공하고 온라인 효율성을 향상시키며 데이터 품질을 향상시킵니다.

SQLE 가져오기

유형 주소
저장소 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 팀은 수백 명의 사람들을 모아 미국으로갔습니다. Huawei는 Yu Chengdong의 직업 변경이 15년 동안 "FFmpeg Pillar of Shame"에 못 박혔다 고 공식 발표했습니다. 이전에는 그랬지만 오늘은 우리에게 감사해야 합니다.— Tencent QQ Video가 과거의 굴욕을 복수한다고요? Huazhong University of Science and Technology의 오픈 소스 미러 사이트가 외부 액세스 보고를 위해 공식적으로 공개되었습니다 . Django는 여전히 74%의 개발자가 선택한 제품입니다. Zed 편집자는 유명한 오픈 소스 회사의 전직 직원이었습니다 . 소식을 전했습니다: 기술 리더는 부하 직원의 도전을 받은 후 격노하고 무례하게 행동하여 해고되었으며 임신했습니다. 여직원 Alibaba Cloud가 공식적으로 Tongyi Qianwen 2.5를 출시했습니다. Microsoft는 Rust Foundation에 100만 달러를 기부했습니다.
{{o.이름}}
{{이름}}

추천

출처my.oschina.net/actiontechoss/blog/11112538