MySQL 5.5.20 作为Master崩溃的原因分析

7月 25th, 2012

Bug现象描述

master为MySQL 5.5.20,slave用MySQL 5.1.49挂起,然后slave执行以下命令:

change master to master_host=’127.0.0.1′, master_user=’backup’, master_password=’1234′, master_port=3306, master_log_file=’mysql-bin.000009′, master_log_pos=***;

若master_log_pos指定的位置出错,则master直接崩溃退出。


重现环境搭建

启动数据库(主库)

D:\mysql\mydata12\master-bin\mysqld.exe –defaults-file=”D:\mysql\mydata12\master-bin\my.ini”

登录数据库(主库)

D:\tnt0326\Src\client\Debug\mysql.exe –defaults-file=”D:\mysql\mydata12\master-bin\my.ini” –uroot

grant replication slave,replication client on *.* to backup@127.0.0.1 identified by ‘1234’;

show master status \G

启动数据库(备库)

MySQL 5.5.20 备库

D:\mysql\mydata12\slave-bin\mysqld.exe –defaults-file=”D:\mysql\mydata12\slave-bin\my.ini”

D:\tnt0326\Src\client\Debug\mysql.exe –defaults-file=”D:\mysql\mydata12\slave-bin\my.ini” -uroot

MySQL 5.1.49 备库

D:\mysql\mydata12\slave51-bin\mysqld.exe –defaults-file=”D:\mysql\mydata12\slave51-bin\my.ini”

D:\tnt0326\Src\client\Debug\mysql.exe –defaults-file=”D:\mysql\mydata12\slave51-bin\my.ini” -uroot

change master to master_host=’127.0.0.1′, master_user=’backup’, master_password=’1234′, master_port=3306, master_log_file=’mysql-bin.000009′, master_log_pos=272;

slave start;

show slave status \G

四种测试用例

测试一:master为MySQL 5.5.20,slave为MySQL 5.1.49

// 在备库执行change master,指定了错误的master_log_pos,start slave之后

// 主库的执行流程

sql_repl.cc::mysql_binlog_send();

heartbeat_period = get_heartbeat_period(thd);

// heartbeat_period = 0

if (heartbeat_period != LL(0))

// coord结构未初始化

coord = &coord_buf;

// 由于指定了错误的master_log_pos,

        // 因此mysql_binlog_send函数执行失败,走到err:位置

err:

// coord未初始化,因此这里的访问直接报错,master退出

my_snprintf(…, coord->file_name, …);

测试二:主备库均为MySQL 5.5.20

// 在备库执行change master,指定了错误的master_log_pos,start slave之后

// 主库的执行流程

sql_repl.cc::mysql_binlog_send();

heartbeat_period = get_heartbeat_period(thd);

// heartbeat_period = 1800000000000(默认取值)

if (heartbeat_period != LL(0))

// coord结构在此分配空间

coord = &coord_buf;

// 由于指定了错误的master_log_pos,

// 因此mysql_binlog_send函数执行失败,走到err:位置

err:

// coord已完成初始化,因此这里执行成功

my_snprintf(…, coord->file_name, …);

测试三:master为MySQL 5.5.25,slave为MySQL 5.1.49

// 在备库执行change master,指定了错误的master_log_pos,start slave之后

// 主库的执行流程

sql_repl.cc::mysql_binlog_send();

heartbeat_period = get_heartbeat_period(thd);

// heartbeat_period = 0

// 无论是否设置heartbeat_period,首先初始化coord结构

start_coord = {log_ident, pos};

p_start_coord = &start_coord;

if (heartbeat_period != LL(0))

// 其他初始化

// 由于指定了错误的master_log_pos,

// 因此mysql_binlog_send函数执行失败,走到err:位置

err:

// p_start_coord结构已经初始化,此处执行成功

my_snprintf(…, p_start_coord->file_name, p_start_coord->pos, …);

测试四:master-slave均为MySQL 5.5.20,但是将slave的master_heartbeat_period设置为0

— 设置master_heartbeat_period参数

— slave > stop slave;

— slave > CHANGE MASTER TO MASTER_HEARTBEAT_PERIOD=0;

— slave > start slave;

// 在slave设置完参数之后,master的执行过程

sql_repl.cc::mysql_binlog_send();

heartbeat_period = get_heartbeat_period(thd);

// heartbeat_period = 0

if (heartbeat_period != LL(0))

// coord结构未初始化

coord = &coord_buf;

// 由于指定了错误的master_log_pos,

// 因此mysql_binlog_send函数执行失败,走到err:位置

err:

// coord未初始化,因此这里的访问直接报错,master退出

my_snprintf(…, coord->file_name, …);

总结

测试一、四,master崩溃。虽然测试一、四,针对的场景Master-Slave场景不同,但是两种崩溃的原因相同,均为heartbeat_period为0,导致coord结构未初始化。此时若指定错误地址,master在出错后,会打印coord中的参数,访问此未初始化结构,导致系统崩溃。

建议

(一)不要使用低版本做Slave连接高版本Master

(二)MySQL 5.5.20附近版本,不要将MASTER_HEARTBEAT_PERIOD参数设置为0

参考资料

http://www.zhaokunyao.com/archives/3134            mysql 主从镜像新功能之heartbeat

  1. prada マトラッセ
    8月 12th, 201319:42

    ダンヒルパリ