MySQL内核月报 2014.11-MySQL· 捉虫动态·SIGHUP 导致 binlog 写错

bug描述

这是5.6中和gtid相关的一个bug,当 mysqld 收到 sighup 信号 (比如 kill -1) 的时候,会 flush binlog,但是新生成binlog开头没写 Previous_gtids_log_event,这会导致下面 2 个问题:

  1. 这个时候 mysqld 重启的话,会发现再也起不来了,error log 里有这样的错

    The binary log file 'mysql/mysql-bin.000020' is logically corrupted: The first global transaction identifier was read, but no other information regarding identifiers existing on the previous log files was found.
  2. 这个时候主库继续更新,然后从库来拉取 binlog 的时候,io 线程会停下来

    Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'Error reading header of binary log while looking for the oldest binary log that contains any GTID that is not in the given gtid set'

bug 分析

mysqld 在收到 sighup 信号后,signal_hand 线程会调用 reload_acl_and_cache 函数 (sql_reload.cc),最终会调用 MYSQL_BIN_LOG::open_binlog,open_binlog 有这段逻辑:


signal_hand 没有调用 store_globals 设置 THR_THD 这个key,所以这个时候 current_thd 得到的值是空的,因此prev_gtids_event 也就不会写进新binlog中的。

2个问题的分析

  1. mysqld 重启不起来的原因:

    mysqld 在启动的时候会通过 mysql_bin_log.init_gtid_sets 来初始化 gtid_executed 和 gtid_purged 2个set,初使化 gtid_executed 时,会读最新的binlog,将文件开头 Previous_gtids_log_event 的 gtid set 和文件里所有的 gtid_event 加起来,放进 gtid_executed,在读文件过程中,如果发现没有 Previous_gtids_log_event ,就报错,程序退出。
  2. 备库的错误信息解释:

    在gtid协议下,主库向备库发 binlog 是用 com_binlog_dump_gtid 函数,这个函数会调到 MYSQL_BIN_LOG::find_first_log_not_in_gtid_set(),这个函数的作用是找到备库需要的第一个 binlog 文件,逻辑是这样的,从编号最大的binlog 往前找,对每个binlog,读取 Previous_gtids_log_event,如果发现这个集合是备库的发来的 gtid_set 的子集,就停止,当前这个binlog文件就是备库需要的第一个binlog文件。找的过程中,如果发现没有 Previous_gtids_log_event,就把错误信息 ER_MASTER_FATAL_ERROR_READING_BINLOG 发给备库。

问题的解决方法

  1. 对server 起不来的,只能手动删所有 binlog 文件了,同时还要清空 binlog.index 文件,有备库的话要重搭备库。
  2. 对于主备场景下,备库停掉的,purge 主库的binlog,如果主备不致的话,比如主库sighup后又有新的更新,这时候需要重做备库,因为binlog已经没了,只能拿主库的数据来重新做一个。

bug 修复

这个bug官方已经修复,具体可以参考 revno: 5908

修复方法类似reload_acl_and_cache 中 REFRESH_GRANT 的逻辑,生成一个临时的 THD 作为 current_thd,在flush logs 完后释放掉。

时间: 2024-09-20 17:38:59

MySQL内核月报 2014.11-MySQL· 捉虫动态·SIGHUP 导致 binlog 写错的相关文章

MySQL内核月报 2014.10-MySQL· 捉虫动态·binlog重放失败

背景 在 MySQL 日常维护中,要回滚或者恢复数据,我们经常会用 binlog 来在数据库上重放,执行类似下面的语句: mysqlbinlog mysql-bin.000001 | mysql -hxxxx -Pxx -u 最近遇到了这样一个问题,在重放 binlog 时,mysqld 报这样的错 ERROR 1064 (42000) at line 25: You have an error in your SQL syntax; check the manual that correspo

MySQL内核月报 2014.08-MySQL· 捉虫动态·Count(Distinct) ERROR

背景 MySQL现行版本中存在一个count(distinct)语句返回结果错误的bug,表现为,实际结果存在值,但是用count(distinct)统计后返回的是0. 原因分析 Count(distinct f)的语义就是计算字段f的去重总数,计算流程大致如下: 流程一: 1. 构造一个unique集合A1(用tree实现) 2. 对每个值都试图插入集合A1中 3. 若和A1中现有item重复则直接跳过,不重复则插入并+1 4. 完成后计算集合中元素个数. 细心的同学会看到上面的语句中有一个s

MySQL内核月报 2014.09-MySQL· 捉虫动态·GTID 和 DELAYED

描述 这是一个MySQL 5.6才有的bug,影响包含最新版本.涉及到的概念有GTID.DELAYED. 现象 在5.6主备都开启GTID-MODE的时候,备库同步线程停止,且Last_SQL_Error显示"When @@SESSION.GTID_NEXT is set to a GTID, you must explicitly set it to a different value after a COMMIT or ROLLBACK. Please check GTID_NEXT var

MySQL内核月报 2014.09-MySQL· 捉虫动态·auto_increment

背景: Innodb引擎使用B_tree结构保存表数据,这样就需要一个唯一键表示每一行记录(比如二级索引记录引用). Innodb表定义中处理主键的逻辑是: 1.如果表定义了主键,就使用主键唯一定位一条记录 2.如果没有定义主键,Innodb就生成一个全局唯一的rowid来定位一条记录 auto_increment的由来: 1.Innodb强烈推荐在设计表中自定义一个主键,因为rowid是全局唯一的,所以如果有很多表没有定义主键,就会在生成rowid上产生争用. row_id由mutex保护,并

MySQL内核月报 2014.10-MySQL· 捉虫动态·从库OOM

bug背景 官方最近发布的版本(5.7.5)修复了这样一个bug,主备复制场景下,如果主库和备库对应的表结构中有数据类型不一致,并且主库的 binlog 是 row 格式的,这时候如果主库对不一致的表做了一个大事务更新,备库在应用 relay-log 的时候报OOM(Out of Memory).bug地址在这里,主备数据类型不一致主要发生在这2种情况下: 主备库版本不一致,不同版本之间的数据类型可能存在不一致.用户在报这个bug时,就是在5.5到5.6的复制场景下,用到了时间类型,时间类型在5

MySQL内核月报 2014.12-MySQL· 捉虫动态·Opened tables block read only

背景 MySQL通过read_only参数来设置DB只读,这样MySQL实例就可以作为slave角色,只应用binlog,不接受用户修改数据.这样就可以保护master-slave结构中的数据一致性,防止双写风险. global read_only的实现方式 MySQL5.5版本通过三个步骤来设置read_only: 步骤1:获取global read lock,阻塞所有的写入请求 步骤2:flush opened table cache,阻塞所有的显示读写锁 步骤3:获取commit lock

MySQL内核月报 2014.09-MySQL· 捉虫动态·GTID 和 binlog_checksum

现象描述 在5.6主备环境下,主备都开启GTID-MODE,备库开启crc校验,主库不开.重启备库sql线程后,备库sql线程停止Last_Error显示:Relay log read failure: Could not parse relay log event entry. The possible reasons are: the master's binary log is corrupted(you can check this by running 'mysqlbinlog' on

MySQL内核月报 2014.10-MySQL· 捉虫动态·崩溃恢复失败

现象 5.6版本,在创建InnoDB表过程中,若发生crash,会导致服务无法启动. 背景 每个InnoDB表A创建成功后有两个文件A.frm和A.ibd.建表流程如下: 1.创建A.frm 2.创建A.ibd 3.初始化A.ibd 4.将表A加入InnoDB字典 若crash发生在步骤2之后,则只保留一个完整的A.frm和一个空文件A.idb. 崩溃恢复 在上述的crash发生后,下一次启动则需要做崩溃恢复.崩溃恢复的一个逻辑是需要遍历数据目录下的所有.ibd文件,验证文件与字典的一致性. 对

MySQL内核月报 2014.11-MySQL· 捉虫动态·OPTIMIZE 不存在的表

bug 描述 这是一个和 GTID 相关的Bug,也就是说5.6才会有,并且出现这个 bug 需要满足条件: 做修改性质的表管理操作,如 OPTIMIZE/ANALYZE/REPAIR 可以,CHECK 就不可以 操作对应的表不存在 gtid_next 被设置为一个固定的值,并且 binlog 开启 在同时满足这3种条件下,会发现记录binlog时,对应的 Gtid_log_event 中的UUID会记为 00000000-0000-0000-0000-000000000000,并且这个对应的