当前位置:首页 > 问答 > 正文

MySQL启动时报错ER_GRP_RPL_FAILED_TO_START_ON_BOOT,远程帮忙修复故障过程分享

(引用来源:某技术社区用户“漂泊的运维”的故障处理帖子)

那天晚上,我正准备下班,手机突然开始嗡嗡作响,一连串的报警短信告诉我,公司那台重要的MySQL数据库服务器重启后,集群服务启动失败了,错误信息就是ER_GRP_RPL_FAILED_TO_START_ON_BOOT,我心里咯噔一下,这意味着MySQL群组复制(Group Replication)在系统启动时没能自己拉起来,业务现在已经中断了。

我赶紧跑回电脑前,用SSH连上了那台服务器,我习惯性地检查MySQL的错误日志,这是寻找线索的第一步,错误日志的路径通常在MySQL的数据目录下,叫hostname.err,我打开日志,快速搜索那个错误代码,果然找到了,日志里除了这个错误,还跟着几行描述,大概意思是“在启动Group Replication插件时发生错误”以及“无法初始化群组通信系统”。

(引用来源:MySQL官方文档关于Group Replication启动阶段的说明)

MySQL启动时报错ER_GRP_RPL_FAILED_TO_START_ON_BOOT,远程帮忙修复故障过程分享

光看这个错误太笼统了,就像医生说“你身体不舒服”一样,没法对症下药,我知道Group Replication的启动依赖于几个先决条件,我决定一步步来排查,我手动尝试启动MySQL服务,看看能不能起来,我输入命令systemctl start mysqld,服务显示启动成功了,这说明MySQL实例本身是好的,问题就出在Group Replication这个插件上。

既然实例能起来,我登录进MySQL命令行,用SELECT * FROM performance_schema.replication_group_members;命令查看集群状态,果然,结果显示当前节点是OFFLINE,整个集群里也看不到其他成员,这说明复制插件根本没加载成功。

我回想了一下Group Replication启动前需要满足的条件,其中一个关键点是,它要求实例在启动时不能应用任何旧的事务日志(比如在崩溃恢复后),MySQL用一个叫gtid_purged的参数来记录已经被清理掉的事务ID集合,如果这个集合和集群其他节点不匹配,或者本身有问题,复制就无法启动。

MySQL启动时报错ER_GRP_RPL_FAILED_TO_START_ON_BOOT,远程帮忙修复故障过程分享

(引用来源:该用户帖子中提到的具体排查命令和思路)

我执行了SHOW GLOBAL VARIABLES LIKE 'gtid_purged';命令,一看结果,我心里有数了,这个gtid_purged的值不是空的,而是包含了一串GTID序列,这说明在本次启动过程中,MySQL可能进行了一些崩溃恢复,并清除了一些事务,对于一个新的、要加入集群的节点,或者一个需要重新初始化的节点来说,这个值应该是空的才对。

问题很可能就在这里,因为gtid_purged非空,Group Replication在启动时会认为这个节点有一些“过去的历史”,它无法保证这些历史事务与集群中的其他节点是一致的,出于数据一致性的考虑,它就直接拒绝启动了。

MySQL启动时报错ER_GRP_RPL_FAILED_TO_START_ON_BOOT,远程帮忙修复故障过程分享

找到嫌疑犯了,下一步就是解决它,但是操作gtid_purged是一个危险动作,因为它直接关系到数据复制的一致性,我必须确保这个节点上的数据是可以被丢弃的,或者说,我打算让它从一个全新的状态重新加入集群(类似于重建从库)。

我再次确认了业务已经全部切走,这个节点暂时没有流量,我执行了重置步骤:先停掉MySQL服务,然后备份了数据目录(以防万一),接着直接删除了数据目录下的所有文件(主要是ibdata1, ib_logfile*, 以及每个数据库的文件夹等),这是一个彻底的重置。

清空数据目录后,我重新初始化MySQL实例(使用mysqld --initialize命令),这会得到一个全新的、没有任何历史数据的环境,初始化成功后,我再次启动MySQL服务,并登录进去。

这一次,我首先检查gtid_purged,确认它是空的,我按照搭建Group Replication集群的流程,重新配置server_idgtid_mode等参数,并安装插件,执行START GROUP_REPLICATION;命令,心跳等待了几秒钟后,再用SELECT * FROM performance_schema.replication_group_members;查看,惊喜地发现节点状态变成了ONLINE,并且成功看到了集群中的其他成员,数据也开始从主节点同步过来了。

为了防止以后再出现类似问题,我仔细复盘了一下,根本原因可能是上次服务器非正常关机(比如断电),导致MySQL在崩溃恢复时留下了不一致的状态,我给服务器配置了UPS(不间断电源),并计划优化一下监控脚本,不仅要监控MySQL服务是否存活,还要监控Group Replication成员的状态是否健康,这次远程抢修总算是有惊无险地完成了。