什么叫做cap
Cap分别指可用性,分区容错性,一致性
分区容错性
如下图中,G1 和 G2 是两台跨区的服务器。G1 向 G2 发送一条消息,G2 可能无法收到。系统设计的时候,必须考虑到这种情况。一般来说,分区容错无法避免,因此可以认为 CAP 的 P 总是成立。所以在cap原则里面,分区容错性是必须要有的
一致性
一致性的意思是,写操作之后的读操作,必须返回该修改后的值。举例来说,某条记录是 v0,然后客户端向 G1 发起一个写操作,将其改为 v1,但是此时注意G2里面的记录还是v0,而不是v1,就像下面这样
然后当用户向G1获取记录的时候,返回就是v1,就像下面这样,这样是没有问题的
但是如果用户向G2服务器获取记录的时候,此时记录还是v0,这就有问题了,因为用户在两个服务获取的记录数据不同,这就是不一致性,怎么解决不一致性呢:我们可以在我们可以在 G1 写操作时,锁定 G2 的读操作和写操作。只有G1完成写操作并且把修改数据同步到G2之后,G2服务器才能重新开放读写操作
为什么可用性和一致性无法都使用
如下图,如果保证 G2 的一致性,那么 G1 必须在写操作时,锁定 G2 的读操作和写操作。只有G1和G2把修改后的数据同步后,才能让G2服务开放读写操作。但是在G2服务器锁定期间,G2 服务器是不能进行读写操作的,所以此时可用性是不可能实现的。
然后如果保证 G2 的可用性,那么势必不能锁定 G2的读写操作,所以刺死一致性不成立。
综上所述,G2 无法同时做到一致性和可用性。系统设计时只能选择一个目标。如果追求一致性,那么无法保证所有节点的可用性;如果追求所有节点的可用性,那就没法做到一致性。
可用性
可用性意思是只要收到用户的请求,服务器就必须给出回应。
为什么可用性和一致性无法都使用
如下图,如果保证 G2 的一致性,那么 G1 必须在写操作时,锁定 G2 的读操作和写操作。只有G1和G2把修改后的数据同步后,才能让G2服务开放读写操作。但是在G2服务器锁定期间,G2 服务器是不能进行读写操作的,所以此时可用性是不可能实现的。
然后如果保证 G2 的可用性,那么势必不能锁定 G2的读写操作,所以刺死一致性不成立。
综上所述,G2 无法同时做到一致性和可用性。系统设计时只能选择一个目标。如果追求一致性,那么无法保证所有节点的可用性;如果追求所有节点的可用性,那就没法做到一致性。
我们在开发过程中cap原则,我们应该怎么选择呢
我们一般都是保证一致性和分区容错性,而舍弃可用性,因为你想啊,一致性对比可用性,还是一致性重要吧,特别是涉及到重要的数据,就比如钱,商品数量,商品价格,如果这些数据你保证可用性,那么就会出现不同时间的访问可能造成数据的不(因为每一次访问的时候可能会访问到不同的服务器),这就大发了,支付宝每一次访问的钱金额不同,你说要命不要命
但是也有使用可用性,而放弃一致性的,举例来说,发布一张网页到 CDN,多个服务器有这张网页的副本。后来发现一个错误,需要更新网页,这时只能每个服务器都更新一遍。一般来说,网页的更新不是特别强调一致性。短时期内,一些用户拿到老版本,另一些用户拿到新版本,问题不会特别大。当然,所有人最终都会看到新版本。所以,这个场合就是可用性高于一致性。
所以cap原则里面到底怎么选,看情况而定
在开发中我们经常遇到zookeeper是使用分区容错性和一致性,而springcloud里面的ribbon的重试机制是保证可用性和分区容错性