zoukankan      html  css  js  c++  java
  • Binlog中table_map_id 的探究

    背景:

    最近,线上Row Based Replication(下称RBR)环境中遇到了一个Bug。这个bug简单的描述就是:RBR对于DML需要通过table-map的event来标注每一个有更新的表。

    而当一个DML同时操作多个表,且其中2个表的mapid相同时(通常为0),会导致slave执行这个event时crash,并重启mysqld实例

    可见这个bug的毁灭性极大。

    那么table-map-id 究竟从何而来?有什么办法知道每个表table-map-id,从而进行一些必要的监控呢?

    下文将用几个例子来进行分析说明。

    1. table-map-id 和 Innodb的table-id是否是同一个概念?

    其实这个问题的答案是显而易见的。因为并非Innodb的表才支持RBR,如果这个问题答案为“是”,那么非innodb的表在RBR中的table-map-id从何而来呢?又怎么保证和innodb的map-id不重复呢?

    所以,显然table-map-id和Innodb数据字典中的table-id是完全不同的两个概念。

    即便如此,下面还是用一个实例进行验证

    create table map_id_test (ID int primary key);
    insert into map_id_test values (1);
    show binlog events in 'log-prefix.000025';

    输出结果:

    Log_name             Pos     Event_type   Server_id    End_log_pos    Info
    log-prefix.000025    2156    Query        15757        2224           BEGIN
    log-prefix.000025    2224    Table_map    15757        2274           table_id: 88 (test.map_id_test)
    log-prefix.000025    2274    Write_rows   15757        2308           table_id: 88 flags: STMT_END_F
    log-prefix.000025    2308    Xid          15757        2335           COMMIT /* xid=346 */

    查看Innodb的table-id:

    select TABLE_ID from INNODB_SYS_TABLESTATS where `SCHEMA`='test' and NAME='map_id_test';

    得到TABLE_ID = 170

    2. table-map-id是否和物理文件有绑定关系

    虽然table-map-id和Innodb的table-id是完全不同的概念。而我们知道Innodb中的table-id和物理文件有绑定关系,即rename table的操作不会改变dict-table中的table-id。

    那么binlog中的table-map-id是不是有可能借鉴了这种实现方式,也有这个特性呢?

    下面是具体测试过程

    set global binlog_format='row';
    create table map_id_test1 (ID int primary key);
    create table map_id_test2 (ID int primary key);
    insert into map_id_test1 values (1);
    insert into map_id_test2 values (1);
    show binlog events in 'log-prefix.000025';

    输出结果如下:此时table1 对应table_id:83 , tabl2 对应table_id:84 

    Log_name             Pos     Event_type   Server_id End_log_pos    Info
    log-prefix.000025    1157    Query        15757     1225           BEGIN
    log-prefix.000025    1225    Table_map    15757     1276           table_id: 83 (test.map_id_test1)
    log-prefix.000025    1276    Write_rows   15757     1310           table_id: 83 flags: STMT_END_F
    log-prefix.000025    1310    Xid          15757     1337           COMMIT /* xid=327 */
    log-prefix.000025    1337    Query        15757     1405           BEGIN
    log-prefix.000025    1405    Table_map    15757     1456           table_id: 84 (test.map_id_test2)
    log-prefix.000025    1456    Write_rows   15757     1490           table_id: 84 flags: STMT_END_F
    log-prefix.000025    1490    Xid          15757     1517           COMMIT /* xid=330 */

    执行rename table,交换table1和table2

    rename table map_id_test1 to map_id_test1_bak,map_id_test2 to map_id_test1, map_id_test1_bak to map_id_test2;

     查看binlog:此时table1 对应table_id:86 , tabl2 对应table_id:87。

    Log_name             Pos     Event_type    Server_id    End_log_pos    Info
    log-prefix.000025    1688    Query         15757        1756           BEGIN
    log-prefix.000025    1756    Table_map     15757        1807           table_id: 86 (test.map_id_test1)
    log-prefix.000025    1807    Write_rows    15757        1841           table_id: 86 flags: STMT_END_F
    log-prefix.000025    1841    Xid           15757        1868           COMMIT /* xid=334 */
    log-prefix.000025    1868    Query         15757        1936           BEGIN
    log-prefix.000025    1936    Table_map     15757        1987           table_id: 87 (test.map_id_test2)
    log-prefix.000025    1987    Write_rows    15757        2021           table_id: 87 flags: STMT_END_F
    log-prefix.000025    2021    Xid           15757        2048           COMMIT /* xid=335 */

    从实验可以得出结论,RBR中的table_id 不仅和物理文件没有绑定关系,在MySQL实例的运行过程中也不是静态不变的。

    因此,大胆猜测,table_id 和file handler有关系。下面的测试将进行验证。

    3. table_id 和file handler是否有直接联系?

    insert into map_id_test1 values (3);
    flush tables;
    insert into map_id_test1 values (4);
    show binlog events in 'log-prefix.000025';

    执行结果: 从结果可以看出,flush table导致了,file handler的重新打开。同时也使table-map-id 发生了变化,且线性递增。

    Log_name             Pos     Event_type    Server_id    End_log_pos    Info
    log-prefix.000025    2424    Query         15757        2492           BEGIN
    log-prefix.000025    2492    Table_map     15757        2543           table_id: 89 (test.map_id_test1)
    log-prefix.000025    2543    Write_rows    15757        2577           table_id: 89 flags: STMT_END_F
    log-prefix.000025    2577    Xid           15757        2604           COMMIT /* xid=383 */
    log-prefix.000025    2604    Query         15757        2679           use `test`; flush tables
    log-prefix.000025    2679    Query         15757        2747           BEGIN
    log-prefix.000025    2747    Table_map     15757        2798           table_id: 90 (test.map_id_test1)
    log-prefix.000025    2798    Write_rows    15757        2832           table_id: 90 flags: STMT_END_F
    log-prefix.000025    2832    Xid           15757        2859           COMMIT /* xid=385 */

    4 代码分析

    出现table_map_id = 0 的主要原因在于下列代码标红部分 (sql_base.cc: line 3079)

    alter table,且不涉及数据更新时,新表的table_map_id 使用了原表已经关闭的table_map_id (此时值为 ~0UL) 。

    mysql表示在5.1.53后修复了这个bug

      /* This list copies variables set by open_table */
      tmp.tablenr=          table->tablenr;
      tmp.used_fields=      table->used_fields;
      tmp.const_table=      table->const_table;
      tmp.null_row=         table->null_row;
      tmp.maybe_null=       table->maybe_null;
      tmp.status=           table->status;
    
      tmp.s->table_map_id=  table->s->table_map_id;
    
      /* Get state */
      tmp.in_use=           thd;
      tmp.reginfo.lock_type=table->reginfo.lock_type;
      tmp.grant=            table->grant;

    结论:

    1. RBR中的Table_ID 和Innodb中的table_id 没有关系,且和物理文件没有对应关系。

    2. Flush Table 可以重置RBR中的Table_ID ,如果有表遇到了map_id=0 的情况,可以使用这个方法尝试解决问题。

    3. 虽然和File Handler 有关,但是和 /proc/$PID/fd/ 中的fd数值没有直接联系

  • 相关阅读:
    Spring session redis
    HttpClient Post Form data and get Response String
    compareTo & toString
    Zookeeper 脑裂
    Maven的HTTP代理设置
    Linux 硬件信息
    [Redis] RDB & AOF
    真实场景中WebRTC 用到的服务 STUN, TURN 和 signaling
    推荐一个VS2015 插件 Favorite Documents
    笔记 Activator.CreateInstance(Type)
  • 原文地址:https://www.cnblogs.com/cenalulu/p/2699907.html
Copyright © 2011-2022 走看看