MySQL半同步复制是一种在异步复制基础上开发的插件机制,可以提供更好的数据持久性,甚至还能提高系统的一致性(稍后将定义该术语)。在高可用性解决方案中,它具有重要作用,但其本身可能会降低系统的可用性。在本文中,我们将介绍半同步复制的一些基础知识,并深入探讨如何通过更高级别的干预措施来保证系统的可用性,避免脑裂问题的发生。

我强烈推荐阅读Jean-François Gagné (简称JFG)的半同步相关博客文章,这些文章详细解析了半同步实现的内部机制,并打破了一些关于半同步复制的迷思。此外,我还建议阅读JFG撰写的关于高可用性和恢复的另一篇文章,这些内容与本篇文章有部分重叠。

备注:在本文中,我们采用“主库(primary)”一词,而不使用传统的“主库(master)”术语。然而,由于目前MySQL配置和状态变量中仍然使用“master”术语,因此在某些地方仍难免出现双重术语的现象。


概述

简单回顾,半同步复制是一种机制,其特性是主库上的事务提交不会直接将数据改动应用到内部表数据或响应用户请求,直到这些改动日志被确保持久化到一个预配置数量的从库中(尽管不一定是应用到表数据)。在讨论范围内,我们将限定版本在MySQL 5.7或同等版本。

具体来说,主库会通过参数rpl_semi_sync_master_wait_for_slave_count进行配置,该参数的值需要大于或等于1才能启用半同步复制。例如,对于一条INSERT事务,主库会在至少指定数量的从库(设定值rpl_semi_sync_master_wait_for_slave_count)确认接收到该事务的日志(即二进制日志条目)后,才报告该事务已提交成功(即返回“OK”响应给用户)。实际上,这意味着至少有该数量的从库已将该日志写入自己的中继日志并确保持久化。这些从库随后会尽可能快地应用这些改动。在本文范围内,我们假设从库没有被故意停止,我们也忽略了那些启用了多种延迟机制的从库。

主库的等待时间由参数rpl_semi_sync_master_timeout决定。如果超时,主库会回退至异步复制模式,这种情况下不再等待指定数量的从库确认日志接收,直接提交并响应用户。在本文讨论范围内,我们感兴趣的是一种“无限超时”场景,我们将其接受为一个非常大的数值。

只有启用了半同步的从库会发送日志接收的确认信号。复制拓扑中可能还存在其他非半同步从库。这些从库同样会拉取从主库发出的日志,但它们并不会发送确认信号。JFG在其文章中指出,半同步从库并不一定是数据最为最新的;可能出现某个非半同步从库在拉取日志数据方面领先于一个甚至所有的半同步从库。


数据持久性

半同步复制最简单直接的应用场景是保证数据的持续性。只有在事务日志被成功写入其他服务器(一台或多台服务器)后,主库才批准一个事务提交。

如前所述,这并不意味着这些日志已经应用到从库对应表数据上。复制可能存在延迟,从库可能由于任务繁重无法及时应用这些日志。但至少在主库宕机情况下,我们可以依赖半同步从库的中继日志中保留的“证据”,以便找出最近的改动记录。


一致性

“一致性”这一术语在分布式系统中有许多不同定义。例如,CAP理论对一致性的定义非常严格:数据写入一台服务器后,任何后续立即在其他服务器上的读取操作都必须返回该写入结果(或任何后续写入结果)。

在本文中,我们采用更宽松的“最终一致性”概念。为了进一步澄清:在主库发生故障的情况下,系统能够在一定时间内(实际期望时间通常很短)促进一个新主库,使其状态与之前主库所展现的状态保持一致,我们认为系统具备一致性。我使用“展现的状态(advertised state)”一词是因为最终用户或应用程序不应对新主库上存在的数据变动感到意外,而无需了解事务或复制的内部机制。


脑裂

脑裂是指有两台服务器同时接受写入操作,而每台服务器都认为自己是单一主库。在脑裂场景下,两台服务器上的数据产生分歧。如果这些服务器还各自拥有从库,则会形成两个分歧的复制树。修复和合并这两个分歧的复制树非常困难,通常需要通过备份和恢复或一些回滚方法让其中一个与另一个保持一致。

需要重申JFG的观察:虽然工程师通常对脑裂持否定态度,但在某些情况下,其对产品的影响可能在可容忍范围内。


拓扑和场景

想获得最佳的数据持久性、一致性、响应时间以及脑裂解决方案,这些需求成本都是很高的。产品负责人和工程师需要在各项指标之间进行合理权衡。

我们来探讨几个配置场景,分析在故障情况下会发生什么。特别关注数据的持久性、是否一致,以及是否可能实现脑裂。


通用场景:等待单个从库,配置多个半同步从库

在这种常见设置中,主库的参数rpl_semi_sync_master_wait_for_slave_count设置为1,并配置多个(多个为超过一个)半同步从库。例如假设有4个半同步从库,分别命名为R1、R2、R3和R4。我们暂名这种模式为“1-n”。

在这种设置中,主库上的写入请求发生后,在批准该请求提交给用户/应用前,该主库等待某个单独从库的确认。哪个从库发送确认无关紧要;对于某些写入请求,它是R1;对于其他写入请求,可能是R4率先发送确认。

重要的是,仅确认的二进制日志事件是有序的,从库确认接收某个日志事件之前,一定已经接收了之前的所有关联日志事件。因此,主库并不关心确认来自于哪个具体的从库。单次确认意味着至少有一个从库完整持久化了所有已提交的事务。



MySQL半同步复制:数据持久性、一致性与脑裂插图

关注公众号:程序新视界,一个让你软实力、硬技术同步提升的平台

除非注明,否则均为程序新视界原创文章,转载必须以链接形式标明本文链接

本文链接:http://www.choupangxia.com/2025/05/19/mysql/