diff --git a/ch09.md b/ch09.md index 380f791..ef08241 100644 --- a/ch09.md +++ b/ch09.md @@ -67,7 +67,7 @@ ## 如何让系统满足线性一致? -线性一致性背后的思想很简单:**让系统表现得好像只有一个数据副本**。但精确的将其拆解开,还需要花很多心思。下面我们来看更多的例子,以更好的理解线性一致性。 +线性一致性背后的思想很简单:**让系统表现得好像只有一个数据副本**。但精确地将其拆解开,还需要花很多心思。下面我们来看更多的例子,以更好得理解线性一致性。 下图显示了三个客户端并发访问提供线性一致性的数据库的同一个键。在分布式系统论文中,x 被称为“**寄存器**”(register)。在实践中,x 可以是一个键值存储中的键值对、关系型数据中的一行或者文档数据中的一个文档。 @@ -120,15 +120,15 @@ 这就是线性一致性背后的一些直觉,[参考文献](https://cs.brown.edu/~mph/HerlihyW90/p463-herlihy.pdf)中有更形式化的定义。可以(但是代价很高)通过记录系统中所有请求的时间线,并检查其能否组成合法的顺序,来测试该系统是否满足线性一致性。 > **线性一致性和可串行化** - +> > **线性一致性**(Linearizability)很容易和**可串行化**(serializability)相混淆,因为他们看起来都像是:可以进行拓扑化组织。但他们是不同维度的约束,我们很有必要对其进行区分: - +> > **可串行化**(Serializability)。可串行化是事务的一种隔离级别。每个事务可能会涉及**多个数据对象**(行、文档、记录)的读写,[之前](https://ddia.qtmuniao.com/#/ch07?id=%e5%8d%95%e5%af%b9%e8%b1%a1%e5%92%8c%e5%a4%9a%e5%af%b9%e8%b1%a1%e6%93%8d%e4%bd%9c)有讨论过单对象和多对象。可串行化可以保证所有事务好像按**某种顺序依次执行**(后一个事务在前一个事务结束后才开始)。需要注意的是,如果某种串行顺序和实际执行顺序不一致也没事,只要是串行执行就行。举个例子,如果 A、B、C 三个事务并发执行,真实顺序是 A->B->C,但如果对应用层表现为 C->A->B 的执行顺序(可能由于多机时间戳不同步),也可以叫可串行化,但 C->A->B 的执行顺序在**某个**对象上可能不满足线性一致性。 - +> > **线性一致性**(Linearizability)。线性一致性是一种针对寄存器(register,**单个数据对象**)的读写新鲜度保证。它不会将多个操作打包成事务,因此不能避免像之前提到的[写偏序](https://ddia.qtmuniao.com/#/ch07?id=%e5%86%99%e5%81%8f%e5%ba%8f%e5%92%8c%e5%b9%bb%e8%af%bb)等问题,除非使用某些辅助手段,如[物化冲突](https://ddia.qtmuniao.com/#/ch07?id=%e7%89%a9%e5%8c%96%e5%86%b2%e7%aa%81)。 - -> 一个数据库可以同时提供可串行化和线性一致性保证,我们称之为**严格可串行化**(_strict serializability_)或者**单副本可串行化**(strong one-copy serializability)。使用两阶段锁或者真正串行化执行实现的可串行化,通常都是线性一致的。 - +> +> 一个数据库可以同时提供可串行化和线性一致性保证,我们称之为**严格可串行化**(*strict serializability*)或者**单副本可串行化**(strong one-copy serializability)。使用两阶段锁或者真正串行化执行实现的可串行化,通常都是线性一致的。 +> > 然而,基于快照隔离的串行化**通常**不是线性一致的。为了避免读写互相阻塞,所有的读取都会基于某个一致性的快照,则该快照之后的写入不会反映到读请求上,因此,快照读不满足线性一致性。 ## 应用线性一致性 @@ -139,7 +139,7 @@ 在使用单主模型的系统中,需要保证任何时刻只有一个主副本,而非多个(脑裂)。一种进行主选举的方法是使用锁:每个节点在启动时都试图去获取锁,最终只有一个节点会成功并且变为主。不论使用什么方式实现锁,都必须**满足线性一致性**:所有节点必须就某节点拥有锁达成一致,否则这样的锁服务是不能用的。 -像 Apache Zookeeper 和 Etcd 之类的协调服务(Coordination services)通常用来实现分布式锁和主选举。他们通常使用共识算法来实现线性一致性操作,并且能够进行容错。当然,在此之上,为了正确的实现锁服务和主选举,还需要讨论一些非常微妙的细节。像 [Apache Curator](https://github.com/apache/curator) 等库可以基于 Zookeeper 提供高层的协调服务抽象。但是,一个提供线性一致性保证的存储服务时实现这些协调任务的**基础**。 +像 Apache Zookeeper 和 Etcd 之类的协调服务(Coordination services)通常用来实现分布式锁和主选举。他们通常使用共识算法来实现线性一致性操作,并且能够进行容错。当然,在此之上,为了正确的实现锁服务和主选举,还需要讨论一些非常微妙的细节。像 [Apache Curator](https://github.com/apache/curator) 等库可以基于 Zookeeper 提供高层的协调服务抽象。但是,一个提供线性一致性保证的存储服务是实现这些协调任务的**基础**。 一些分布式数据库在**更细粒度上**使用了分布式锁,如 Oracle Real Application Clusters(RAC)。当有多个节点共同访问同一个磁盘存储系统时,RAC 会为每个磁盘页配一把锁。由于这些线性化的锁是事务执行的关键路径,RAC 通常将其部署在和数据节点使用专线连接起来的集群里。 @@ -157,7 +157,7 @@ 这些约束都要求所有节点在**单个最新值**(账户余额、股票水位、座位预定)上达成一致。 -当然,在真实场景下,有时这些约束课可以被适当放宽(比如,如果机票座位被超订了,可以将其中一个用户移到其他航班,并给与适当补偿)。在这种情况下,可能不需要严格的线性一致性,稍后我们会在及时性和完整性一节讨论这些放松的约束。 +当然,在真实场景下,有时这些约束可以被适当放宽(比如,如果机票座位被超订了,可以将其中一个用户移到其他航班,并给予适当补偿)。在这种情况下,可能不需要严格的线性一致性,稍后我们会在及时性和完整性一节讨论这些放松的约束。 但是对于像我们平时在关系型数据库中看到的严格的唯一性约束,就需要线性一致性了。数据库中其他类型的一些约束,如外键约束和属性约束,就可以不用借助线性一致性来实现了。 @@ -191,14 +191,14 @@ - **共识算法**(Consensus algorithms,linearizable) 我们本章稍后会讨论到,有一些共识算法,看起来与单主模型类似。但这些共识协议有一些阻止脑裂和过期副本的手段。由于这些额外细节,共识算法可以实现安全的线性一致性存储。Zookeeper 和 etcd 就是用的这种手段。 - **多主模型**(Multi-leader replication,not linearizable) - 由于可以同时在多个节点上处理写入,并且异步同步写入数据,使用多主模型的系统通常不是线性一致的。由于上述原因,这种系统可能会产生需要手动解决的写入冲突。这种冲突便是违反线性一致性要求的一个点:表现的像一个副本。 + 由于可以同时在多个节点上处理写入,并且异步同步写入数据,使用多主模型的系统通常不是线性一致的。由于上述原因,这种系统可能会产生需要手动解决的写入冲突。这种冲突便是违反线性一致性要求的一个点:表现得像一个副本。 - **无主模型**(Leader replication, probably not linearizable) 对于使用无主模型的系统(Dynamo-style,参见前面[无主模型](https://ddia.qtmuniao.com/#/ch05?id=%e6%97%a0%e4%b8%bb%e6%a8%a1%e5%9e%8b)一节)来说,厂商有时候会声称你可以通过使用法定数目读写(Quorum reads and write,w+r > n)来获得强一致性。这个说法有点模糊,并不总是正确,这取决于你对法定节点的配置,也取决于你如何定义强一致性。 “后者胜”(Last write win)的冲突解决方法会依赖于多个机器的挂历时钟(time-of-day,参见[依赖时钟同步](https://ddia.qtmuniao.com/#/ch08?id=%e4%be%9d%e8%b5%96%e5%90%8c%e6%ad%a5%e6%97%b6%e9%92%9f)),由于多机时钟存在偏差,其物理时间戳不能保证和系统事件顺序一致,因此基本上不可能做到线性一致。放松的法定策略(Quorum,见[放松的 Quorum 和提示转交](https://ddia.qtmuniao.com/#/ch05?id=%e6%94%be%e6%9d%be%e7%9a%84-quorum-%e5%92%8c%e6%8f%90%e7%a4%ba%e8%bd%ac%e4%ba%a4))也是破坏了线性一致性。即使对于严格的法定策略,非线性一致的现象也可能出现,下一节将会详细探讨。 ### 线性一致和法定策略(Quorum) -从直觉出发,在 Dynamo 风格的系统重使用严格的 Quorum 读写应该会满足线性一致性。但在具有不确定延迟的网络中,仍然可能会出现竞态条件。如下图所示: +从直觉出发,在 Dynamo 风格的系统中使用严格的 Quorum 读写应该会满足线性一致性。但在具有不确定延迟的网络中,仍然可能会出现竞态条件。如下图所示: ![Untitled](img/ch09-fig06.png)