MySQL 5.7 GTID OOM bug案例分析 --大量压测后主从不同步

时间:2024-01-06 15:11:02

转载自:http://www.sohu.com/a/231766385_487483

MySQL 5.7是十年内最为经典的版本,这个观点区区已经表示过很多次。然而,经典也是由不断地迭代所打造的传奇。5.7给我印象最深的莫过于各种OOM,比如线程池、XA事务、information_schema等OOM的各种场景,之前在网易时就遇到了不少。

遇到OOM问题是非常令人头疼的,因为这类问题可能是最难排查的故障,复现需要很长的时间。好在5.7的performance_schema能够各种维度监控MySQL的内存使用情况,使得DBA拥有了一定的线索或可能来排查问题,具体可见一年之前发表的文章:MySQL 5.7 OOM问题诊断——就是这么简单

OOM问题虽烦人,但至少说明负责的DB业务相对是比较大的。若能遇到并解决这样的问题,无疑level就会+1,成就+1,这不就是DBA应该追求的挑战么?只喝咖啡刷微信群,又如何能够成为业界Top 5(前5%)的DBA?

今天分享最近在线上遇到的一例OOM问题实战。简单来说,若满足下面条件,则你线上的从机DB必然会遇到OOM问题:

  • MySQL version <= 5.7.17;
  • 开启了GTID和GTID合并功能;
  • Slave设置super_read_only=1;

MySQL 5.7引入了表gtid_executed,解决了开启GTID必须要开启参数log_slave_updates的小困扰,因为开启log_slave_updates会多写一份二进制日志,存储会有一定额外的开销。具体见:MySQL 5.7中新增的表gtid_executed,看看是否解决了你的痛点。

若启用GTID并且不启用线程log_slave_updates,则表gtid_executed会不断增大,每次事务提交会将当前GTID写入到该表。为了避免此表不断增大,MySQL引入GTID合并线程thread/sql/compress_gtid_table,定期来合并这张表。参数gtid_executed_compression_period用来控制GTID合并的频率。

然而,在MySQL 5.7.17及之前的版本中,当从机设置super_read_only = 1时,MySQL会认为当前是只读的,应该阻止所有DML操作,因此GTID合并线程也会失败,而失败的GTID合并线程会不断地重试。此外,由于合并失败,表gtid_executed的记录数会不断增大,合并所需占用的内存不断增加,从而导致OOM。

通过命令SHOW ENGINE INNODB STATUS可以看到类似如下的情况:

mysql >SHOW ENGINE INNODB STATUSG

......

---TRANSACTION 7629816744, ACTIVE 402 sec rollback

mysql tables in use 1, locked 1

ROLLING BACK 287907 lock struct(s), heap size 32514256, 59334816 row lock(s), undo log entries 33575312

MySQL thread id 3, OS thread handle 139678174787328, query id 0 Compressing gtid_executed table

......

mysql > SELECT COUNT(1)

-> FROM mysql.gtid_executedG

****** 1. row ******

COUNT(1): 59334816

1 row in set (19.97 sec)

可以发现ID为3的线程一直处于回滚状态,持有的记录锁近6000W。而从MySQL 5.5版本开始记录锁的内存从操作系统申请,而不再通过BP分配,所以当表gtid_executed不断增大时,最终会导致MySQL OOM。

另外一个异常状态是,虽然从机开启了只读选项,但线上的DML统计值依然非常大:

Number of rows inserted 5096110378, updated 120106820, deleted 71297166352, read 76453180531

将参数log_slave_updates设置为0,模拟原5.6的场景能否绕过这个bug呢?很可惜,依然不能。因为表gtid_executed虽然不再实时更新,然而每次二进制日志rotate时,依然会更新表gitd_executed。而这时GTID合并线程依然会被激活,只是OOM所需的时间可能会要更长。

MySQL 5.7.18虽然修复了这个bug,具体可查github提交,bug号:#84332。然而此修复却引入了新的bug,相信很多同学可能已经遇到过类似如下的问题:

The MySQL server is running with the --super-read-only option so it cannot execute this statement

所以如果想要彻底的解决上述问题,务必升级到MySQL 5.7.19。当然5.7.19版本还解决了并行复制可能导致主从数据不一致的bug。总之,尽快升级到最新的MySQL 5.7.22。为什么是5.7.22版本而不是19呢?因为MySQL团队继MGR后又放出了一个超大招,下篇文章姜老师将揭晓哦。