当前位置: 首页 > news >正文

分布式环境下的主从数据同步

目录

1. 数据同步的推/拉方式

2.复制方式

2.1 同步复制

2.2 异步复制

2.3 半同步复制

2.4 常见组件的同步方式

3.日志格式

3.1 基于语句复制 SBR

3.2 基于行复制 RBR

3.3 基于预写日志 WAL

3.4 基于触发器复制

4.不同复制架构下的同步机制

4.1 单主复制 Single Leader

4.2 多主复制 Multi Leader

4.3 无主复制 LeaderLess

4.4 分片集群 Sharding

5.主从数据一致性问题

5.1 写后读一致性

5.2 单调读

5.3 一致前缀读


1. 数据同步的推/拉方式

从数据同步如何触发的角度来看,有两种常见模式:

  • 主节点推送:当主节点数据变更时,主动向所有从节点推送新数据
  • 从节点拉取:从节点定期询问主节点是否有数据更新,有则拉取新数据

常见组件的推拉方式:

组件

同步方式

MySQL

从节点拉取(通过binlog实现)

Etcd

主节点推送(raft 协议同步数据) + 从节点拉取(心跳)

MongoDB

从节点拉取(副本集通过 oplog 实现)

Redis

从节点拉取(异步复制) + 主节点推送(首次全量同步)

ZooKeeper

主节点推送(ZAB 协议同步数据) + 从节点拉取(心跳)

2.复制方式

2.1 同步复制

leader 节点等待所有 follower 节点确认已接收到并处理完数据后,才执行后续操作。

这种方式保证了数据的高度一致性,但可能会导致性能瓶颈,特别是在网络延迟较高的情况下。

适用场景:高一致性要求、分布式协调(如 etcd 的 raft 协议)

2.2 异步复制

leader 节点不需等待 follower 返回,直接继续后续操作。

这意味着数据可能不会立即同步到所有 follower 节点上,从而可能导致短暂的数据不一致。但是这种方法通常具有更好的性能表现。

适用场景:日志分析、社交媒体等一致性要求不高的系统

2.3 半同步复制

介于同步复制和异步复制之间的一种折衷方案。在这种模式下,只要一个 follower 返回之后,leader 就可以进行下一步操作。

这种方式既保证了一定程度的数据一致性,又避免了完全同步复制带来的性能损耗。

适用场景:MySQL 半同步复制、MongoDB 的 w:majority 模式

注意:共识算法并不是半同步模式而是强同步模式,因为半同步只需 1 个节点返回即可,存在数据丢失风险;但是共识算法要求多数节点返回,是严格保证一致性的。

2.4 常见组件的同步方式

组件

默认同步方式

一致性级别

其他同步方式支持

MySQL

异步

可调(最终→强)

支持半同步(插件配置,需至少1个从节点确认),

组复制(多数节点同步)

PostgreSQL

同步(流复制)

可调

可配置为异步(synchronous_commit=off),

支持同步提交(remote_apply严格同步)

MongoDB

异步

可调(w:1→w:majority)

通过写关注(Write Concern)配置半同步(如w:majority+j:true)

Redis

异步

弱一致性

可使用WAIT命令,手动等待指定个数的节点复制完成,但本质还是异步的

Etcd

同步(Raft)

强一致性

不支持

Kafka

异步(acks=1)

可调

acks=all(等待所有节点确认),

min.insync.replicas控制最小同步副本数

比如查询 mysql binLog 的同步方式:

SHOW VARIABLES LIKE 'sync_binlog';

有三种配置:

  • 0 - 不主动刷盘,由操作系统决定何时刷盘(安全性差,数据易丢失)
  • 1 - 每次提交事务时刷盘(安全性高,性能差)(默认值)
  • N - 每N次提交后刷盘(平衡安全性和性能)

3.日志格式

3.1 基于语句复制 SBR

基于语句的复制(SBR, Statement-Based Replication):leader 记录下它执行的每个语句(INSERT/UPDATE/DELETE)的日志,把日志发给 follower,每个 follower 解析并执行语句。

这种方式生成的数据量小, 所以磁盘 IO 次数少,因此性能也不错。但是会导致 follower 上生成不同的数据,如使用 NOW()、RAND()、自增 ID、基于现有数据 UPDATE 等。

基于语句的复制在 mysql 5.1 之前使用,现在默认已经不再使用。

3.2 基于行复制 RBR

基于行的复制(RBR, Row-Based Replication):记录每行数据的变化,当数据被修改时,生成的日志包含被修改行的唯一标识,以及所有列的新值。

这种方式由于复制的是原始数据,不会出现数据不一致的情况,但是缺点是数据量大,磁盘 IO、网络开销也高。

这种方式是 mysql binLog 现在默认的复制方式。可以通过命令查询:

SHOW VARIABLES LIKE 'binlog_format’;

有三种配置:

  • Statement: 基于语句复制
  • Row: 基于行复制(默认值)
  • Mixed: Statement 与 Row 混合(默认使用 Statement,涉及日期、函数相关时用 Row)

可以看出 mysql binLog 和 redis 复制方式刚好对应,redis 也是三种:

  • RDB:全量同步
  • AOF:增量同步
  • 混合模式

3.3 基于预写日志 WAL

预写日志(WAL, Write-Ahead Logging):在数据实际写入存储之前,先记录所有变更到日志(prepare状态),等待后台异步刷盘后,再将日志中的变更更新到数据文件(commit状态),所以 WAL 本质上是一种两阶段提交

这种方式适用于大多数类型的数据库。如 mysql 的 redoLog,etcd 的 raft log,pg 的 WAL,都是用的预写日志方式。

注意:WAL 和 RBR/SBR 并不冲突,比如 mysql 就是两种协调工作的: 

  • binLog 使用 RBR/SBR,工作在 Server 层,用于确保数据在多个节点上的一致性
  • redoLog 使用 WAL,工作在 InnoDB 引擎层,用于确保数据在单个节点上不丢失

关于 mysql 的几种日志可以看: (十一)MySQL日志篇,总结得相当之好了。

3.4 基于触发器复制

利用数据库的触发器功能,在特定事件发生时自动触发复制逻辑。虽然灵活性强,但由于依赖于数据库内部机制,维护成本较高。

4.不同复制架构下的同步机制

4.1 单主复制 Single Leader

只有一个主节点负责写操作,其余节点均为只读副本。

典型应用:mysql、pg、mongoDB副本集、etcd。

这是最常见也是最简单的复制模型,易于管理和维护,数据一致性强,但在高并发写入场景下可能存在瓶颈。

4.2 多主复制 Multi Leader

允许多个节点同时接受写操作。

典型应用:CouchDB、Cassandra、多活MySQL集群。

这种架构提高了系统的可用性和容错能力,但数据一致性较差,需要解决冲突。

冲突检测与解决机制:

  • 最后写入胜利(LWW):基于时间戳选择最新值(可能丢数据)
  • 客户端解决:应用层合并冲突(如Git的合并冲突)
  • CRDTs(无冲突数据类型):数据结构本身支持自动合并(如计数器、集合)

4.3 无主复制 LeaderLess

没有明确的主节点概念,所有节点地位平等,均可接受读写请求。

典型应用:Dynamo、Cassandra、ScyllaDB。

此架构容错性高,非常适合分布式环境下的大规模部署,但同样数据一致性差。

常见技术:

  • 读写仲裁(Quorum):写入时需成功W个节点,读取时需查询R个节点,满足W + R > N(N为副本总数)以保证一致性
  • hinted handoff:节点不可达时,其他节点暂存数据并在恢复后转发
  • 反熵(Anti-Entropy):后台进程定期同步节点间的差异数据

4.4 分片集群 Sharding

分片是一种水平拆分数据的架构模式,将数据集按特定规则(如哈希、范围)分布到多个节点上,每个节点只存储部分数据。

常见分片方式:

  • 哈希分片: 对分片键(如用户ID)计算哈希值,按哈希范围分配数据。如 redis、mongoDB、es
  • 范围分片: 按分片键的范围(如时间戳、ID区间)分配数据。如 mysql 分库分表
  • 目录分片: 维护一个动态查找表,记录数据与分片的映射关系。如 zookeeper

分片通常与复制结合使用,构成分片+副本的混合架构:

  • 分片层: 数据水平拆分到多个逻辑组
  • 副本层: 每个分片由一个主节点和多个从节点组成

5.主从数据一致性问题

5.1 写后读一致性

场景:用户写入数据后立刻读取,读到了 follower 节点,此时这条数据尚未同步,导致读到旧数据。

解决:

  • 如果是读用户自己的数据,则强制读主
  • 写入时记录时间戳,读取时确保从节点的数据时间 ≥ 写入时间戳
  • 写入后客户端将数据缓存,优先从缓存查询

5.2 单调读

场景: 同一用户连续多次读取时,可能看到数据回退(先读到新值,再读到旧值)。

解决:

  • 会话粘滞: 同一用户的请求始终路由到同一个节点
  • 客户端记录上次读取的版本号(时间戳),后续只接受 ≥ 该版本的数据

5.3 一致前缀读

场景:不同写入操作因网络乱序到达从库,导致读取到因果颠倒的数据。比如先看到 B 回复 A,再看到 A 的发言。

解决:

  • 跟踪写入的因果依赖关系(如向量时钟),确保从库按顺序更新
  • 使用全局有序日志(如共识算法),保证所有节点顺序写入

参考:

https://dev.mysql.com/doc/refman/8.0/en/replication-formats.html

(十一)MySQL日志篇之undo-log、redo-log、bin-log.....傻傻分不清!任何项目都会有日志,M - 掘金

(二十四)全解MySQL之主从篇:死磕主从复制中数据同步原理与优化主从复制是一种十分常见的高可用手段,MQ、Redis、 - 掘金

两万字长文解析raft算法原理

相关文章:

  • SpringBoot事务管理(四)
  • Faster-Whisper —— 为语音识别加速的利器
  • 283. 移动零
  • 【QT】Qt4 QtWebKit使用教程
  • 数据结构与算法-双指针法
  • Java 大视界 -- 基于 Java 的大数据可视化在城市规划决策支持中的交互设计与应用案例(164)
  • 30-超市进销存管理系统
  • RAG 高效检索利器 打造企业 “规章制度智能体”(ollama + deepseek + langchain + MinerU)
  • 力扣经典算法篇-5-多数元素(哈希统计,排序,摩尔投票法)
  • CES Asia 2025:行业话语权的逐鹿高地
  • 如何利用系统的数据分析能力提高利润额?
  • websocket获取客服端真实ip
  • Linux | I.MX6ULL 终结者底板原理图讲解(5)
  • 最新万能场馆预约系统源码 基于ThinkPHP+UniApp 含图文搭建部署教程
  • Python+新版DeepSeek V3轻松开发Agent
  • Unity跨平台输入系统
  • Doris Streamloader安装教程
  • LeetCode 78.子集
  • 字符函数,日期函数笔记
  • QinQ-端口安全
  • 做外贸网站公司哪家好/网站监测
  • 广告网站建设流程/百度seo搜索营销新视角
  • wap移动建站系统/百度竞价投放
  • 小猫mip网站建设/石家庄seo关键词排名
  • 什么网站没人做/sem是什么测试
  • 电商seo推广/seo品牌优化