1 推荐的文章
下面这篇知乎文章是我见过的最简单易懂的一篇,把CAP定义以及为什么AP和CP只能二选一以及场景特定下选AP还是CP作为系统目标等讲解明明白白
谈谈分布式系统的CAP
2 个人对上面这篇文章的的一些补充
可用性可以人为设置一个阈值,比如用户体验很差,响应时间过长,比如系统宕机算作是不可用
可用性指“Reads and writes always succeed”,即服务在正常响应时间内一直可用。
好的可用性主要是指系统能够很好的为用户服务,不出现用户操作失败或者访问超时等用户体验不好的情况。
其实证明可用性和一致性不能同时在分布式系统满足主要看请求阻塞和非阻塞情况下系统的表现和带来的问题,一般阻塞请求会满足一致性,但是会违背可用性,不阻塞请求则相反。而阻塞和非阻塞二者不可得兼,所以可用性和一致性也不能得兼,得证
这篇知乎贴主给我举了一个为什么不能同时实现AP和CP的例子,我做一些补充:
1 一个分布式系统也可以是主从架构部署的,假设N1和N2分别是主从mysql数据库,N1是主结点,N2是N1的从结点,N1可负责读写,N2只负责读,这时操作M同步的可能是主结点N1刚刚写入磁盘的数据,如果N1,N2结点之间的网络坏了,无法正常通信,但是用户的读请求量大的时候,会被负载均衡到N1和N2,从N1读取的数据是最新的数据,但是如果用户想要读取N2结点的这个刚刚更新的数据时候,会有两种情况,
(1)一是如果要保证数据的一致性,用户请求需要等待N1和N2之间的网络通信恢复,这可能会超时等待(可能无法在指定的时间内正常响应),这就导致可用性无法得到保证
(2)二是如果要保证可用性,那么不等N1和N2之间的网络通信恢复,N2直接将旧有的数据返回给用户,这样一致性无法得到保证。
下面这个图中的分布式网络大概对应这种情况
这个案例和redis的主从架构的数据同步导致的一致性问题非常相似,redis主从架构是保证了AP但不保证CP的,至于证明可以参考以下链接的1.2:从分布式理论到如何做一个生产级别的分布式锁
但是1.2还缺少一个证明,为什么redis主从架构可以容忍主结点宕机后的数据不一致(Consistency)
答:快+高可用+数据丢失一部分可以接受,为什么可以丢失一部分数据呢?因为最终的数据持久化到了mysql中,redis仅仅是内容的副本,即使数据丢了也可以在mysql中得真实数据。
2 一个分布式系统,可以是主-主架构的,N1和N2都可以读写,其过程和1没有什么太大的区别
3 一个分布式系统,可以是我们的后端微服务系统,假设每一个微服务可以部署在一台独立的服务器上,服务P部署在N1上,Q部署在N2上,现在要调用服务P,但是服务P要调用服务Q,但是突然服务Q某所有实例宕机了,这个时候,如果一定要等待该服务正常上线或者被替换才会做出响应(阻塞),那么满足一致性但会让用户请求等待过长时间,如果不阻塞,服务P在服务Q规定时间内没有做出响应的时候会返回一个默认值给用户(比如说请求失败,商品购买失败),那么就不满足一致性,但是保证了可用性。这个例子说明了快速响应是可用性的一个重要指标,尽管这个响应可能不正确!
4 一个分布式系统,可以是redis与mysql组成的系统,redis用作缓存,mysql用作持久化存储,两者涉及到数据一致性问题,商品信息需要放到redis中用作缓存,比如现在我需要修改mysql数据库中的某一件商品,假设我们目前采取先更新数据库再删除缓存的同步策略,即先往mysql中更新数据,再删除掉redis缓存,那么在更新mysql数据库到删除掉redis缓存成功的这段时间,允许请求继续查询redis该更改过的商品信息,获得的是旧数据,这就违背了一致性原则,但是如果我现在要求这个分布式系统必须百分百保证一致性,那么所有的读该商品信息的请求是不是就得在更新数据库到删除缓存这段时间被阻塞住,如果请求量过大,阻塞队列过长,那么请求的响应时间过长(超出正常的限定值),这个时候就违背了可用性原则,以上阻塞用户请求读取redis缓存直到数据完全一致则会违背可用性问题,而不阻塞的话,会违背一致性问题,这就是经典的可用性和一致性不能同时在分布式系统满足的经典案例。