复制的原因:
- 使得数据与用户在地理上接近(从而减少延迟)
- 即使系统的一部分出现故障,系统也能继续工作(从而提高可用性)
- 伸缩可以接受读请求的机器数量(从而提高读取吞吐量)
复制的困难之处在于处理复制数据的变更(change)。
常见的变更复制算法:单领导者(single leader),多领导者(multi leader)和无领导者(leaderless)
1 领导者与追随者
存储数据库副本的每个节点称为 副本(replica)。
基于领导者的复制(Leader-based replication),也称主动/被动,也称主/从(master/slave)复制。
- 副本之一指定为领导者/主库,其他副本称为追随者/只读副本
- 从数据库读取数据时,可以向主库或从库查询;但只有主库能接受写操作。
- 每当领导者将新数据写入本地存储时,它也会将数据变更发送给所有的追随者,称之为复制日志(replication log)记录或变更流(change stream)。每个跟随者从领导者拉取日志,并相应更新其本地数据库副本,方法是按照领导者处理的相同顺序应用所有写入。
同步复制与异步复制
复制是同步的还是异步的。
半同步(semi-synchronous):一个跟随着是同步的,其他的是异步的。
通常情况下,基于领导者的复制都配置为完全异步。优点是即使所有从库都落后了,主库也可以继续写入;缺点是无法保证持久。
设置新从库
在数据库运行时,设置新的从库。
从概念上的过程如下:
- 某一时刻获取主库的一致性快照
- 将快照复制到从库
- 从库连接到主库,并拉取快照之后的所有数据变更
- 当从库处理完快照之后积压的数据变更,我们说它赶上(caught up)了主库。现在它可以继续处理主库产生的数据变化了。
处理节点宕机
通过基于主库的复制实现高可用。
- 从库失效:追赶恢复
从库从日志中得知故障前的最后一个事务,然后请求在这之后的所有数据变更,应用这些变更以追赶上主库。
- 主库失效:故障切换(failover)
主库失效,需要将一个从库提升为主库。
故障切换的过程:
- 确认主库失效。一般使用超时来确认。
- 选择新主库。选举。
- 重新配置系统以启用新主库。
复制日志的实现
- 基于语句的复制
- 传输预写式日志(Write Ahead Log, WAL)
- 逻辑日志复制(基于行)
- 基于触发器的复制
2 复制延迟问题
3 多主复制
4 无主复制
最早的一些复制数据系统是无领导的。但在关系数据库主导的时代,无领导方式较少使用。
Riak,Cassandra和Voldemort是由Dynamo启发的无领导复制模型的开源数据存储,所以这类数据库也被称为 Dynamo风格。
在无领导配置中,故障切换不存在。那么,加入节点故障时,如何保证读取的数据是最新的呢?
解决:当一个客户端从数据库中读取数据时,它不仅仅发送它的请求到一个副本:读请求也被并行地发送到多个节点。客户可能会从不同的节点获得不同的响应。即来自一个节点的最新值和来自另一个节点的陈旧值。版本号用于确定哪个值更新。
Dynamo风格经常使用 2 种机制保证数据复制到每一个副本上:读修复(read repair)和反熵过程(anti-entropy process)
- 读修复
- 反熵过程
