写在前面

本文隶属于专栏《100个问题搞定大数据理论体系》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢!

本专栏目录结构和文献引用请见100个问题搞定大数据理论体系

解答

在工程中常用的一致性模型有:强一致性(Strong Consistency), 弱一致性(Weak Consistency),最终一致性(Eventual Consistency 

1. 强一致性:系统中的某个数据被成功更新后,后续任何对该数据的读取操作都将得到更新后的值。所以在任意时刻,同一系统所有节点中的数据是一样的。
2. 弱一致性:系统中的某个数据被更新后,后续对该数据的读取操作可能得到更新后的值,也可能是更改前的值。但经过“不一致时间窗口”这段时间后,后续对该数据的读取都是更新后的值
3. 最终一致性:是弱一致性的特殊形式。存储系统保证,在没有新的更新的条件下,最终所有的访问都是最后更新的值。

补充

强一致性

在强一致性系统中,只要某个数据的值有更新,这个数据的副本都要进行同步,以保证这个更新被传播到所有备份数据库中。
在这个同步进程结束之后,オ允许服务器来读取这个数据。

所以,强一致性一般会牺牲一部分延迟性,而且对于全局时钟的要求很高。

最终一致性

在最终一致性系统中,我们无需等到数据更新被所有节点同步就可以读取。
尽管不同的进程读同一数据可能会读到不同的结果,但是最终所有的更新会被按时间顺序同步到所有节点。
所以,最终一致性系統支持异步读取,它的延迟比较小。

其他

除了以上三个,分布式系统理论中还有很多别的一致性模型,如顺序一致性( Sequential Consistency),读写一致性(read-your-writes consistency),因果一致性( Casual Consistency)等。

顺序一致性

当程序在各个处理机上并行运行时,所有处理机(或进程)对同一个存储器的访问是同样顺序进行的。

读写一致性

手机刷虎扑的时候经常遇到,回复某人的帖子然后想马上查看,但我刚提交的回复可能尚未到达从库,看起来好像是刚提交的数据丢失了,很不爽。

在这种情况下,我们需要读写一致性,也称为读己之写一致性。

它可以保证,如果用户刷新页面,他们总会看到自己刚提交的任何更新。它不会对其他用户的写入做出承诺,其他用户的更新可能稍等才会看到,但它保证用户自己提交的数据能马上被自己看到。

如何实现读写一致性?

  1. 最简单的方案,对于某些特定的内容,都从主库读。举个例子,知乎个人主页信息只能由用户本人编辑,而不能由其他人编辑。因此,永远从主库读取用户自己的个人主页,从从库读取其他用户的个人主页。 如果应用中的大部分内容都可能被用户编辑,那这种方法就没用了。在这种情况下可以使用其他标准来决定是否从主库读取,例如可以记录每个用户最后一次写入主库的时间,一分钟内都从主库读,同时监控从库的最后同步时间,任何超过一分钟没有更新的从库不响应查询。

  2. 还有一种更好的方法是,客户端可以在本地记住最近一次写入的时间戳,发起请求时带着此时间戳。从库提供任何查询服务前,需确保该时间戳前的变更都已经同步到了本从库中。如果当前从库不够新,则可以从另一个从库读,或者等待从库追赶上来。

单调读

用户从某从库查询到了一条记录,再次刷新后发现此记录不见了,就像遇到时光倒流。如果用户从不同从库进行多次读取,就可能发生这种情况。

单调读可以保证这种异常不会发生。单调读意味着如果一个用户进行多次读取时,绝对不会遇到时光倒流,即如果先前读取到较新的数据,后续读取不会得到更旧的数据。单调读比强一致性更弱,比最终一致性更强。

实现单调读取的一种方式是确保每个用户总是从同一个节点进行读取(不同的用户可以从不同的节点读取),比如可以基于用户ID的哈希值来选择节点,而不是随机选择节点。

因果一致性

因果一致性往往发生在分区(也称为分片)的分布式数据库中。 分区后,每个节点并不包含全部数据。不同的节点独立运行,因此不存在全局写入顺序。

如果用户A提交一个问题,用户B提交了回答。问题写入了节点A,回答写入了节点B。因为同步延迟,发起查询的用户可能会先看到回答,再看到问题。

为了防止这种异常,需要另一种类型的保证:因果一致性。 即如果一系列写入按某个逻辑顺序发生,那么任何人读取这些写入时,会看见它们以正确的逻辑顺序出现。

因果一致性类似于Java内存模型里面的 happens-before 原则。

因果一致性是一个听起来简单,实际却很难解决的问题。

一种方案是应用保证将问题和对应的回答写入相同的分区。但并不是所有的数据都能如此轻易地判断因果依赖关系。如果有兴趣可以搜索向量时钟深入此问题。

在实际应用系统中,强一致性是很难实现的,应用最广的是最终一致性。

实践

对于微信朋友圈的评论功能,你觉得哪种一致性模型更适用?为什么?

最终一致性,因果一致性,读写一致性

微信朋友圈评论主要由评论和后续回复组成。

1. 对于评论,评论内容对评论者而言应该要保证读写一致性(read-your-writes consistency),即评论一旦发出,那么对于该评论者无论在手机、网页还是其它城市应该都能看到其之前写的评论。
2. 而对于朋友圈可见的其它人来说,只要保证最终一致性(eventual consistency)就可以了(可能有时间要求),不同人的评论读取顺序无需和真实发生的顺序保持一致。
3. 对于评论的后续回复。回复内容对于回复者而言应该要保证读写一致性(read-your-writes consistency)。
4. 而其它朋友圈可见的人一样,评论和回复內容应该按顺序被读取到,重要的是对于某一条评论的评论必须显示在派生这条评论的原始评论之后,否则用户读起来会很混乱,此时就需要因果一致性。

Q.E.D.


大数据开发工程师,精通 Spark,擅长 Java 和 Scala