CAP理论

CAP 理论#

一致性(Consistency) 可用性(Availability) 分区容错性(Partition Tolerance)

一致性#

一致性说的是客户端的每次读操作,不管访问哪个节点,要么读到的都是同一份最新的数 据,要么读取失败。你可以看到,一致性强调 的不是数据完整,而是各节点间的数据一致。比如 kv 系统又两个节点,初始 x=1,当客户端发送 set x=2 到节点 1,节点 1 修改数据 x=2 同时通知节点 2 修改 x=2, 都修改成功后节点 1 才返回修改成功给客户端。

问题:如果节点 2 出现故障,那么节点 1 一直不能返回修改成功给客户端,造成系统不可用。

可用性#

可用性说的是任何来自客户端的请求,不管访问哪个节点,都能得到响应数据,但不保证是 同一份最新数据。你也可以把可用性看作是分布式系统对访问本系统的客户端的另外一种承 诺:我尽力给你返回数据,不会不响应你,但是我不保证每个节点给你的数据都是最新的。 这个指标强调的是服务可用,但不保证数据的一致。

问题:客户端访问不同节点,数据可能不一致

分区容错性#

当节点间出现任意数量的消息丢失或高延迟的时候,系统仍然可以继续提供服务。也就是说,分布式系统在告诉访问本系统的客户端:不管我的内部出现什么样的数据同步问题,我会一直运行,提供服务。这个指标,强调的是集群对分区故障的容 错能力。作为分布式系统来说,内部节点出现故障是一定的,所有这个特性是一定要考虑的。

CAP 只能三个选两个,而 P 是一定要考虑的,所有设计系统一般是一致性和可用性二选一。

追求一致性 CP#

就是实现分布式系统的 ACID 特性,需要用到分布式事务协议,比如二阶段提交协议 和 TCC(Try-Confirm-Cancel)

二阶段提交协议(第一次先问其他节点能不能做,全部回答能做才第二次提交,有一个不能就返回失败给客户端)#

比如三个节点,客户端连接节点 1 发送一个操作,节点 1 就是协调者(Coordinator),协调者通过两次提交统一结果,返回给客户端(全部执行或者全部不执行)

在第一个阶段,每个参与者投票表决事务是放弃还是提交。一旦参与者投票 要求提交事务,那么就不允许放弃事务。也就是说,在一个参与者投票要求提交事务之前, 它必须保证能够执行提交协议中它自己那一部分,即使参与者出现故障或者中途被替换掉。 这个特性,是我们需要在代码实现时保障的。

缺点:第一次提交的时候,所有节点就要把需要操作的数据锁住,保证最终能够执行成功。这会影响系统的并发性能。

TCC(Try-Confirm-Cancel)#

TCC 是 Try(预留)、Confirm(确认)、Cancel(撤销) 3 个操作的简称,它包含了预 留、确认或撤销这 2 个阶段。客户端同时通知三个节点预留资源,当客户端都收到预留成功时,再同时通知三个节点确认操作。这个其实是由代码来实现的。

追求可用性 AP#

AP 模型没有固定的模型,但是根据实际经验来说,AP 分布式系统的核心理论就是基本可用(Basically Available)和最终一致性(Eventually consistent)

基本可用实现#

流量削峰、延迟响应、体验降级、过载保护这 4 板斧,更能理解这 4 板斧背后的妥协折中,从而灵活地处理不可预知的突发问题。

最终一致性#

系统中所有的数据副本在经过一段时间的同步后,最终能够达到一个一致的状态。也就是说,在数据一致性上,存在一个短暂的延迟。

如果业务的某功能无法容忍一致性的延迟 (比如分布式锁对应的数据),需要实现的是强一致性;如果能容忍短暂的一致性的延迟 (比如 QQ 状态数据),就可以考虑最终一致性。

实现最终一致性的具体方式是什么?#

读时修复:在读取数据时,检测数据的不一致,进行修复

写时修复:在写入数据,检测数据的不一致时,进行修复。具体来说,Cassandra 集群的节点之间远程写数据的时候,如果写失败就将数据缓存下来,然后定时重传,修复数据的不一致性(性能消耗小)。

异步修复:这个是最常用的方式,通过定时对账检测副本数据的一致性,并修复。

Gossip 协议#

这个协议可以达到最终一致性

Gossip 的三板斧分别是:直接邮寄(Direct Mail)、反熵(Anti-entropy)和谣言传播 (Rumor mongering)。

直接邮寄:就是直接发送更新数据,当数据发送失败时,将数据缓存下来,然后重传。比如节点 1 向节点 2,3 发送数据,但是返回失败,节点 1 会把数据写入队列缓存,不断的去通知节点 2,3. 直到通知成功。

缺点:缓存队列满了后,写不进去,就会导致最终不一致。

反熵指的是集群中的节点,每隔段时间就选择某个其他节点,然后通过互相交换自己的 所有数据来消除两者之间的差异,实现数据的最终一致性。常用的是节点组成一个闭环,比如节点 a->b->c->a->b. 这样所有节点的数据就保持一致了。这个要求所有节点都已知。

谣言传播,广泛地散播谣言,它指的是当一个节点有了新数据后,这个节点变成活跃状态, 并周期性地联系其他节点向其发送新数据,直到所有的节点都存储了该新数据。当节点数不确定时,可以使用。

Quorum NWR 算法#

要灵活地自定义一致性,可以自定义一致性的级别。

比如我们实现了一个 AP 系统,可以达成最终一致性,但是突然有个需求,我们要拉这几个业务的数据做实时分析,希望数据写入成功后,就能立即读取到新数据,也就是要实现强一致性。

强一致性能保证写操作完成后,任何后续访问都能读到更新后的值;

最终一致性只能保证如果对某个对象没有新的写操作了,最终所有后续访问都能读到相 同的最近更新的值。也就是说,写操作完成后,后续访问可能会读到旧数据。

在原有系统上开发实现一个新功能,就可以满足业务同学的需求了。因为通过 Quorum NWR,你可以自定义一致性级别,通过临时调整写入或者查询的方式,当 W + R > N 时,就可以实现强一致性了。常用的 AP 系统中,Quorum NWR 是通常都会实现的一个功能,可以满足某些强一致性的场景。

Quorum NWR 的三要素#

N 表示副本数,又叫做复制因子(Replication Factor)。也就是说,N 表示集群中同一份数据有多少个副本。在实现 Quorum NWR 的时候,你需要实现自定义副本的功能。也就是 说,用户可以自定义指定数据的副本数

W,又称写一致性级别(Write Consistency Level),表示成功完成 W 个副本更新,才完成写操作,比如设置 write level = 2, 表示这个写操作要完成了 2 副本的更新才算写成功。

R,又称读一致性级别(Read Consistency Level),表示读取一个数据对象时需要读 R 个副本。你可以这么理解,读取指定数据时,要读 R 副本,然后返回 R 个副本中最新的那份数据。Read level =2.

本作品采用《CC 协议》,转载必须注明作者和本文链接
走出舒适区