驯服双头龙 - 高并发下 MySQL 双主问题的解决之道
在上一篇博客里,我们直面了 MySQL 双主架构的种种“麻烦”:无情的写入冲突、必然的自增 ID 碰撞、恼人的复制延迟、可怕的脑裂风险以及步步惊心的 DDL 操作。这些问题在高并发环境下会被急剧放大。但这并不意味着双主架构就完全不可用,关键在于我们是否采取了正确的策略来规避或缓解这些风险。
直面冲突:处理写入冲突的策略
这是双主架构中最核心的问题,尤其是在尝试双活写入(Active-Active Write)时。
-
策略 A:应用层数据分区 (Application-Level Partitioning) - [推荐]
- 核心思想:从业务逻辑或数据本身入手,设计路由规则,确保特定范围的数据永远只会被写入到固定的一个主库。这是避免冲突最有效的方法。
- 实现举例:
- 按用户 ID 哈希或范围:用户 ID 模 2 为 0 的写 Master A,模 2 为 1 的写 Master B。
- 按业务功能:订单库写 Master A,用户库写 Master B。
- 按地域:中国区写 Master A,海外区写 Master B。
- 优缺点:
- 优点:从根本上消除了对同一数据的并发写入可能,数据一致性得到保障。
- 缺点:需要在应用层或中间件实现路由逻辑;牺牲了写入的灵活性;单主库故障时,其负责的数据写入需要能切换到另一个主库(可能临时打破分区,需考虑恢复)。
-
策略 B:主动-被动写入模式 (Active-Passive Write Approach) - [推荐]
- 核心思想:放弃用双主做写入负载均衡的想法,主要将其用于高可用故障切换。平时,指定一个主库(如 Master A)为 Active Master,处理所有或绝大部分写请求;另一个主库(Master B)为 Passive Master,只处理读请求或极少量不会冲突的写(如日志)。只有当 Active Master 宕机时,才通过流量切换(手动或自动)将 Passive Master 提升为 Active 状态处理写入。
- 优缺点:
- 优点:极大降低了写入冲突的概率,架构相对简单,易于管理。
- 缺点:无法实现写入能力的水平扩展;需要可靠的故障检测和切换机制。
-
策略 C:冲突检测与解决 - [不推荐自行实现]
- 核心思想:允许冲突发生,然后通过技术手段(如增加时间戳/版本号字段、触发器、或第三方工具如
pt-table-sync
)去检测不一致,并按预定规则(如后写入覆盖、特定字段优先等)修复。 - 评价:实现非常复杂,容易出错,修复过程可能丢失数据或引入新的不一致,且检测和修复本身有性能开销。除非有成熟的商业解决方案或极强的自研能力,否则强烈不建议在标准双主架构中依赖这种方式。
- 核心思想:允许冲突发生,然后通过技术手段(如增加时间戳/版本号字段、触发器、或第三方工具如
告别碰撞:解决自增 ID 冲突
这是一个必须解决的问题,否则复制将无法正常工作。
-
方案 A:设置不同的
auto_increment_increment
与offset
- [标准方案]- 原理:让两台服务器生成不重叠的 ID 序列。通常设置步长
auto_increment_increment
- 原理:让两台服务器生成不重叠的 ID 序列。通常设置步长