<b>bug背景</b>
人为直接的连上从库 alter 表
<b>bug分析</b>
为啥数据类型不一致会导致 oom 呢?oom 表示程序在持续申请内存,把内存给用爆了。从库的slave thread在应用rows_log_event时,如果发现主库的表和从库的表不兼容,就会创建一个临时中间表,做数据转化:
在此过程中用的临时表结构和field字段都是从thd的mem_root分配的,而每个rows_log_event应用时分配内存空间再do_apply_event后就不会再用了,但是 rows_log_event::do_apply_event() 结束后并没有free_root释放,而是在事务所有event做完后释放的。类似下面这种包含大量更新语句的事务,每一个更新对应一个rows_log_event,备库在应用时,在事务执行中间所有申请的内存都会保持,如果语句非常多的话,就导致oom了。
<b>bug 修复</b>
像 query_log_event::do_apply_event() 在结束会调用free_root,来释放thd->mem_root空间,而rows_log_event::do_apply_event()却不能这样干,因为在下面的场景下,用户的线程会调用 rows_log_event::do_apply_event()
mysqlbinlog mysql-bin.00000x | mysql -hxxxx -pxx -u
如果在中间释放用户线程的thd->mem_root的话,会有问题。
因此官方的修复方法是在log_event类构造函数初始化一个属于log_event的 mem_root
在析构函数里释放
然后把rows_log_event::do_apply_event()本来从thd->mem_root申请的内存改为从自身的 m_event_mem_root 申请,这样每个event应用完,被delete时其转化过程中申请的内存也一并被释放,避免了oom的产生。