《数据密集型应用系统设计》读书笔记整理(5)-- 数据复制


一个可能出错的事物与一个不可能出错的事物之间的主要区别是,当一个不可能出错的事物出错了,通常也就意味着不可修复。
——Douglas Adams,《基本无害》(1992)

复制主要指通过互联网络在多台机器上保存相同数据的副本。使用复制的一些目的:

  • 使数据在地理位置上更接近用户,从而降低访问延迟。
  • 当部分组件出现故障,系统依然可以继续工作,从而提高可用性。
  • 扩展至多台机器以同时提供数据访问服务,从而提高读吞吐量。

有三种流行的复制数据变化的方法:主从复制、多主节点复制和无主节点复制。

主从复制

主从复制工作原理:主副本把新数据写入本地存储后,然后将数据更改作为复制的日志或更改流发送给所有从副本,每个从副本获得更改日志后将其应用到本地,且严格保持与主副本相同的写入顺序。

复制一个重要的设计选项是同步复制还是异步复制。

  • 同步复制的优点是一旦确认写入,从节点可以明确保证完成了与主节点的更新同步。但如果同步的从节点无法完成确认时,写入就不能视为成功,会导致主节点阻塞。同步复制实现中一般是设置某个从节点是同步的,而其它节点是异步的,可保证至少有两个节点拥有最新的数据副本。这种配置称为半同步。

  • 异步模式的优点在于不管从节点数据多滞后,主节点总是可以继续响应写请求,系统的吞吐性能更好。但无法保证数据的持久化。

处理节点失效

从节点失效:追赶式恢复
主节点失效:节点切换

复制日志的实现

1.基于语句的复制

将每个主节点执行的操作语句作为日志发送给从节点。

这种复制方式会有不适用的场景:

  • 调用非确定性函数的语句,比如NOW()获取时间。
  • 有副作用的语句(触发器、存储过程、用户定义的函数等),可能会在每个副本上产生不同的副作用。
2.基于预写日志(WAL)传输

缺点:日志描述的数据结果非常底层,使得复制方案和存储引擎紧密耦合,不同版本的存储引擎很有可能无法支持复制。

3.基于行的逻辑日志复制

复制和存储引擎采用不同的日志格式,将复制和存储逻辑剥离。这种复制日志称为逻辑日志。
由于逻辑日志与存储引擎逻辑解耦,可以更容易保持向后兼容。对于外部应用程序来说,逻辑日志格式也更容易解析,该技术称为变更数据捕获。

4.基于触发器的复制

复制滞后问题

如果从一个异步复制的从节点和主节点发起相同的查询,可能会得到不同的结果。这种不一致只是一个暂时的状态,如果停止写主节点,经过一段时间后,从节点会最终赶上并与主节点保持一致。这种效应被称为最终一致性。

读自己的写

在异步复制的数据库里,写之后马上读,可能新数据还没有更新到从节点,这时,我们需要读写一致性。

基于主从复制系统实现读写一致性:

  • 如果用户访问可能会被修改的内容,从主节点读取,否则,在从节点读取。
  • 应用程序或中间件判断是否应该从主节点读取,例如更新后一分钟内,从主节点读取。
单调读

单调读一致性可以确保不发生数据向后回滚的情况。可以让每个用户总是从固定的同一副本执行读取。

前缀一致读

在给分区数据库写入多个记录后读取,有可能从不同分区获取到的数据因果关系发生了颠倒,这类异常需要前缀一致读来防止。

多主节点复制

对主从复制模型进行自然扩展,配置多个主节点,每个主节点都可以独立接受写操作,同时处理写的每个主节点将数据更改转发到所有其它节点。这称为多主节点复制,此时,每个主节点还同时扮演其它主节点的从节点。此方案较适用于多数据中心。

在多数据中心环境下,部署单主节点和多主复制方案的差异:

  • 性能。对于主从复制,所有写入必须传送至主节点所在的数据中心,会增加写入延迟,与多数据中心的就近访问理念背道而驰。而多主节点模型中,每个写操作都可以在对应的数据中心得到快速响应,再异步复制到其他数据中心。
  • 容忍数据中心失效。主从复制时,如果主节点数据中心发生故障,必须切换至另一个数据中心并提升一个从节点为主节点。在多主节点模型中,每个数据中心可以独立于其它数据中心继续运行。
  • 容忍网络问题。数据中心之间的通信一般不如数据中心内部的本地网络可靠。主从复制模型对网络性能和稳定性会更加依赖。多主节点模型可以更好容忍此类问题。

处理写冲突

多主复制的最大问题是如何处理写冲突。而处理冲突最理想的策略是避免发生冲突。

当多个主节点写入数据发生冲突时,最终数据库必须以一种收敛趋同的方式来解决冲突,即所有副本的最终值是相同的。

  • 给每个写入分配一个ID(时间戳、随机数、UUID等),挑选最高的ID的写入作为胜利者,并将其它写入丢弃。如果基于时间戳,称为最后写入者获胜。这种方法可能会造成数据丢失。
  • 每个副本分配一个唯一的ID,并制定规则,例如序号高的副本始终优先于序号低的。这种方法也可能会造成数据丢失。
  • 以某种方式将值合并在一起。
  • 利用预定义好的格式来记录和保留冲突相关的所有信息,然后依靠应用层的逻辑事后解决冲突。

无主节点复制

无主节点复制模型选择放弃主节点,允许任何副本直接接受来自客户端的写请求。亚马逊内部使用Dynamo系统,基于无主复制架构。

Dynamo风格的数据存储系统经常使用下面两种机制在副本之间同步最新数据:

  • 读修复
    当客户端并行读取多个副本时,可以检测到过期的值,并把新值写入包含旧值的副本。

  • 反熵过程
    通过一个后台进程不断查找副本之间数据的差异,将任何缺少的数据从一个副本复制到另一个副本。

读写quorum

如果有n个副本,写入需要w个节点确认,读取必须至少查询r个节点,则只要w + r > n,读取的节点中一定会包含最新值。
满足上述r、w值的读/写操作称为法定票数(或仲裁)读/写。之所以肯定能读到最新值,是因为成功写入的节点集合和读取的节点集合必然有重合,这样读取的节点中至少有一个具有最新值。


参考文献:
[1] (美)Martin Kleppmann. 数据密集型应用系统设计(赵军平,吕云松,耿煜,李三平 译)[M]. 北京:中国电力出版社,2018.

Published

Author

Levin

Category

Web Arch

Tags

web arch database book report
Disqus loading now...