复制的原因:

  • 使得数据与用户在地理上接近(从而减少延迟)
  • 即使系统的一部分出现故障,系统也能继续工作(从而提高可用性)
  • 伸缩可以接受读请求的机器数量(从而提高读取吞吐量)

复制的困难之处在于处理复制数据的变更(change)
常见的变更复制算法:单领导者(single leader)多领导者(multi leader)无领导者(leaderless)

1 领导者与追随者

存储数据库副本的每个节点称为 副本(replica)。

基于领导者的复制(Leader-based replication),也称主动/被动,也称主/从(master/slave)复制。

  • 副本之一指定为领导者/主库,其他副本称为追随者/只读副本
  • 从数据库读取数据时,可以向主库或从库查询;但只有主库能接受写操作
  • 每当领导者将新数据写入本地存储时,它也会将数据变更发送给所有的追随者,称之为复制日志(replication log)记录或变更流(change stream)。每个跟随者从领导者拉取日志,并相应更新其本地数据库副本,方法是按照领导者处理的相同顺序应用所有写入。


同步复制与异步复制

复制是同步的还是异步的。

半同步(semi-synchronous):一个跟随着是同步的,其他的是异步的。

通常情况下,基于领导者的复制都配置为完全异步。优点是即使所有从库都落后了,主库也可以继续写入;缺点是无法保证持久。

设置新从库

在数据库运行时,设置新的从库。
从概念上的过程如下:

  1. 某一时刻获取主库的一致性快照
  2. 将快照复制到从库
  3. 从库连接到主库,并拉取快照之后的所有数据变更
  4. 当从库处理完快照之后积压的数据变更,我们说它赶上(caught up)了主库。现在它可以继续处理主库产生的数据变化了。

处理节点宕机

通过基于主库的复制实现高可用。

  • 从库失效:追赶恢复

从库从日志中得知故障前的最后一个事务,然后请求在这之后的所有数据变更,应用这些变更以追赶上主库。

  • 主库失效:故障切换(failover)

主库失效,需要将一个从库提升为主库。
故障切换的过程:

  1. 确认主库失效。一般使用超时来确认。
  2. 选择新主库。选举。
  3. 重新配置系统以启用新主库。

复制日志的实现

  • 基于语句的复制
  • 传输预写式日志(Write Ahead Log, WAL)
  • 逻辑日志复制(基于行)
  • 基于触发器的复制

2 复制延迟问题

3 多主复制

4 无主复制

最早的一些复制数据系统是无领导的。但在关系数据库主导的时代,无领导方式较少使用。
Riak,Cassandra和Voldemort是由Dynamo启发的无领导复制模型的开源数据存储,所以这类数据库也被称为 Dynamo风格

在无领导配置中,故障切换不存在。那么,加入节点故障时,如何保证读取的数据是最新的呢?
解决:当一个客户端从数据库中读取数据时,它不仅仅发送它的请求到一个副本:读请求也被并行地发送到多个节点。客户可能会从不同的节点获得不同的响应。即来自一个节点的最新值和来自另一个节点的陈旧值。版本号用于确定哪个值更新。

Dynamo风格经常使用 2 种机制保证数据复制到每一个副本上:读修复(read repair)和反熵过程(anti-entropy process)

  • 读修复
  • 反熵过程