天天看点

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

<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-&gt;mem_root空间,而rows_log_event::do_apply_event()却不能这样干,因为在下面的场景下,用户的线程会调用 rows_log_event::do_apply_event()

mysqlbinlog mysql-bin.00000x | mysql -hxxxx -pxx -u

如果在中间释放用户线程的thd-&gt;mem_root的话,会有问题。

因此官方的修复方法是在log_event类构造函数初始化一个属于log_event的 mem_root

在析构函数里释放

然后把rows_log_event::do_apply_event()本来从thd-&gt;mem_root申请的内存改为从自身的 m_event_mem_root 申请,这样每个event应用完,被delete时其转化过程中申请的内存也一并被释放,避免了oom的产生。