- Consistency @ (强)一致性:系统的所有节点在相同时刻可以看到相同数据,即对于在多个节点中存在的变量而言,其在同一时刻的值必然是相同的;
- Availability @ 可用性:无论响应结果如何,系统都可以“在合理的时间内”响应请求,即使节点因为各类故障(包含但不限于网络分区)而不可用;
- Partition Tolerance @ 分区容错性:系统能够在发生(特指)网络分区时继续响应请求。
所谓CAP理论指的是分布式系统无法在“读/写数据”时同时满足“一致性/可用性/分区容错性”三种特性,因此系统设计者必须在这三者之间做出权衡:
- CA策略 @ 一致性&可用性:牺牲分区容错性来保证一致性&可用性。CA策略不属于分布式系统的可用策略,因为以目前的技术能力而言网络分区是无法避免的。因此如果放弃了分区容错性,那么分布式系统在网络分区时将完全不可用。但该策略在单机部署&单点集群部署(服务虽然被多个部署为集群,但相互间没有交互)时是可用的,或者说单机部署&单点集群部署的程序默认就是CA策略,因为其内部不存在网络交互,因此也就无需在意网络分区的发生。所有程序&系统在服务未拆分/未集群的情况下采用的都是CA策略;
- CP策略 @ 一致性&分区容错性:牺牲可用性来保证一致性&分区容错性,适用于对数据一致性要求较高的分布式系统。当网络分区发生时,如果节点A无法正常请求节点B以完成数据同步,那么其可以通过阻塞至网络恢复的方式(并非只有这一种方式)来保证分区容错性。这种方式同时还可保证一致性,因为其可保证数据的读/写一定是正确的。但与此同时该方法会牺牲可用性,因为阻塞可能会导致请求难以/无法被及时回应。在实际情况中,从节点A复制数据到节点B总是需要花费一定时间的。如果是跨地域(例如北京到广州)的机房,耗费的时间就可能是几十/几百毫秒。因此CAP理论中的C在实践中是不可能完美实现的,因为在数据复制的过程中节点A&B 的数据并不一致,但CAP理论并不在意这种延迟。ZooKeeper就是一个典型的CP系统,它采用分布式一致性算法(如Paxos/Raft等)来确保在不同节点之间就数据状态达成强一致。此外,分布式一致性算法通常都带有容错特性,即只追求多数一致而非完全一致,故而大多数CP系统可用性其实也相当可观;
- AP策略 @ 可用性&分区容错性:牺牲一致性来保证可用性&分区容错性,适用于对可用性较高的场景。当节点故障/网络分区发生时,如果节点A无法正常请求节点B以完成数据同步,那么其可以通过放弃请求的方式(并非只有这一种方式)来保证分区容错性。这种方式同时还可保证可用性,因为其确保了回应必然是及时的。但与此同时该方法会牺牲一致性,因为请求将难以/无法正确地读/写数据。AP策略通常依赖“最终一致性”模型进行弥补,即虽然会有一定的延迟,但数据最终还是会在一定时间内会达成一致。
CAP理论策略的选择不是一成不变的。在 CAP理论落地实践时,我们需要将系统数据按照不同的应用场景和要求进行分类,从而为每类数据选择不同的分布式策略,而不是直接限定整个系统的所有数据都使用同一策略。
CAP理论告诉我们必须“牺牲”三特性中的一个,但这里的“牺牲”其实有一定误导作用,因为“牺牲”让很多人理解成彻底放弃。但实际上CAP理论的“牺牲”只是说我们无法在节点故障/网络分区期间保证一致性/可用性,而现实情况是系统在整个生命周期的大部分时间里·都是正常的,发生节点故障/网络分区现象的时间并不长。例如4个9 @ 99.99%可用性的系统一年运行下来不可用的时间只有50分钟;而5个9 @ 99.999%可用性的系统一年运行下来不可用的时间更是只有5分钟而已。在节点故障/网络分区期间放弃一致性/可用性并不意味着永远放弃,我们可以在节点故障/网络分区期间进行一些操作,从而令分布式系统在故障解决后重新达到一致性&可用性的状态。