本文是《数据密集型应用系统设计》(DDIA)的读书笔记,一共十二章,我已经全部阅读并且整理完毕。
采用一问一答的形式,并且用列表形式整理了原文。 笔记的内容大概是原文的 1/5 ~
1/3,所以你如果没有很多时间看书的话,看我的笔记也就够了!
复制的目的:
如果复制的数据不会随时间而改变,那复制就很简单:复制一次即可。
复制的难点在于复制数据的变更。
三种流行的变更复制算法:
复制时的权衡:使用同步复制还是异步复制?如何处理失败的副本?
主从复制工作原理:
复制系统的一个重要细节是:复制是 同步(synchronously) 发生还是 异步(asynchronously) 发生。
以用户更新头像为例:
同步复制:
半同步:通常使用一个从库与主库是同步的,而其他从库是异步的。这保证了至少两个节点拥有最新的数据副本。
通常情况下,基于领导者的复制都配置为完全异步。注意,主库故障可能导致丢失数据。
有时会增加一个新的从库。
过程:
我们的目标:即使个别节点失效,也要能保持整个系统运行,并尽可能控制节点停机带来的影响。
自动故障切换:
故障切换会出现很多大麻烦:
基于主库的复制,底层工作有几种不同的复制方式。
在最简单的情况下,主库记录下它执行的每个写入请求(语句(statement))并将该语句日志发送给其从库。
问题:
第三章告诉我们,写操作通常追加到日志中:
所以,日志都是包含所有数据库写入的仅追加字节序列。可以使用完全相同的日志在另一个节点上构建副本:主库把日志发送给从库。
PostgreSQL和Oracle等使用这种复制方法。
缺点:
采用逻辑日志,可以把复制与存储逻辑分离。
关系型数据库通常以行作为粒度描述数据库写入的记录序列:
优点:
如果用户把数据提交到了主库,但是主从有延迟,用户马上看数据的时候请求的从库,会感觉到数据丢失。
此时需要「读写一致性」,也成为读己之写一致性。
技术:
用户有多个设备时,还要考虑的问题:
用户可能会遇到时光倒流。
第一次请求到从库看到了评论,第二次请求到另外一个从库发现评论消失。
单调读保证了这种异常不会发生。
方法:
一系列事件可能出现前后顺序不一致问题。比如回答可能在提问之前发生。
这是分区(分片)数据库中的一个特殊问题:不同分区之间独立,不存在全局写入顺序。
需要「一致前缀读」。
方法:
运维多个数据中心时,单主和多主的适应情况比较:
性能
容忍数据中心停机
容忍网络问题
多主复制的缺点:
实现冲突合并解决有多种途径:
解决冲突的最合适方法取决于应用程序。
写时执行
读时执行
规则复杂,容易出错。
防止无限复制循环:
环形和星形拓扑的问题
全部到全部拓扑的问题
读修复(Read repair)
反熵过程(Anti-entropy process)
计算方式
但是,即使在 w + r > n w + r> n w+r>n 的情况下,也可能存在返回陈旧值的边缘情况。
不要把 w 和 r 当做绝对的保证,应该看做是概率。
强有力的保证需要事务和共识。
问题
权衡
宽松的法定人数(sloppy quorum)
提示移交(hinted handoff)
优点
缺点
在传统意义上,一个宽松的法定人数实际上不是一个法定人数。
常见使用中,宽松的法定人数是可选的。
写入顺序问题举例:
思路
方法:最后写入胜利
优点
缺点
使用场景
一个算法,可以确定两个操作是否是并发的,还是先后关系。
两个客户端同时向一个购物车添加项目,注意版本号:
操作依赖关系:
服务器可以通过查看版本号来确定两个操作是否是并发的,算法的原理:
当一个写入包含前一次读取的版本号时,它会告诉我们的写入是基于之前的哪一种状态。
优点
缺点
Riak 称这些并发值为兄弟。
合并兄弟值:
容易出错,所以有了一些数据结构设计出来。
多个副本,但是没有领导者,该怎么办?
版本向量
复制可以用于几个目的:
高可用性
即使在一台机器(或多台机器,或整个数据中心)停机的情况下也能保持系统正常运行
断开连接的操作
允许应用程序在网络中断时继续工作
延迟
将数据放置在距离用户较近的地方,以便用户能够更快地与其交互
可伸缩性
能够处理比单个机器更高的读取量可以通过对副本进行读取来处理
我们讨论了复制的三种主要方法:
单主复制
客户端将所有写入操作发送到单个节点(领导者),该节点将数据更改事件流发送到其他副本(追随者)。读取可以在任何副本上执行,但从追随者读取可能是陈旧的。
多主复制
客户端发送每个写入到几个领导节点之一,其中任何一个都可以接受写入。领导者将数据更改事件流发送给彼此以及任何跟随者节点。
无主复制
客户端发送每个写入到几个节点,并从多个节点并行读取,以检测和纠正具有陈旧数据的节点。
我们研究了一些可能由复制滞后引起的奇怪效应,我们也讨论了一些有助于决定应用程序在复制滞后时的行为的一致性模型:
写后读
用户应该总是看到自己提交的数据。
单调读
用户在一个时间点看到数据后,他们不应该在某个更早的时间点看到数据。
一致前缀读
用户应该将数据视为具有因果意义的状态:例如,按照正确的顺序查看问题及其答复。
最后,我们讨论了多领导者和无领导者复制方法所固有的并发问题:因为他们允许多个写入并发发生,这可能会导致冲突。我们研究了一个数据库可能使用的算法来确定一个操作是否发生在另一个操作之前,或者它们是否同时发生。我们还谈到了通过合并并发更新来解决冲突的方法。