CAP原理还记得不
C:一致性
A:可用性
P:分区容错性
C代表的是强一致性,A代表的是可用性,P代表某个分区出问题的时候整个集群依然可用。
为什么说金属发展的进步就是从CP到AP呢?
因为C会消耗相当大的资源,在大数据高并发的情况下,集群则会给业务更多的支撑,但集群最怕的敌人则是强一致性,尤其是replicate的模式下,所有集群的副本相同的情况下,性能的损耗会是巨大的。举个例子,我们有一个集群分别是A、B、C、D、E,每个集群下都有全量的副本,集群的目的是为了减少读取压力,让读取分散到五个实例上。那么,当A中添加了一条数据后,需要通知其他四个实例,并且,确定四个实例都没有问题之后,返回给A,告知实例同步结束,整个集群才会变成可用的。这中间是有几种情况的:
方案1:A同步到B、C、D、E上的时候,A是否可用,也就是说,A是有全量数据的,BCDE是没有的,这时我们是否可以让A对外提供服务,而BCDE在接收全量数据之前,对外隐藏,也就是说此时整个实例可用,有且只有A对提供服务,这样会不会很好?既解决了时效性,有让集群高度可用呢?实际上这里有一个隐藏的风险,A在同步数据的时候,是有IO输出的,而这个过程如果出现大量的读写操作,IO资源会被强占,会出现阻塞;也就是说,外界的IO会给A造成不稳定因素,会导致A同步其他实例出现大量延时,或者,读取速度很慢,最坏的情况,A会崩溃,丢掉这次读写的所有数据。
方案2:A同步到B、C、D、E上的之前,整个集群不可用。好处是集群会比较稳定,保持强一致性,坏处显而易见,在这个过程中,集群不会对外提供服务,暂不可用,这就是做到了C,就无法做到A了。例如:ZK
方案3:A同步到B,当确定A到B同步完成后,A对外提供服务,B异步同步到C、D、E上,做到最终一致性。这样的好处是,A同步到B的稳定性要远远好于同步到所有的集群,把风险降维1/N,只需要选择一台网络通信性能最好的作为B,由B完成所有的同步,当同步完成时,实例唤醒,对外提供服务。MYSQL目前默认采用这种方案。
上面三种方案,其实都是在描述如何提供一个CP的集群方案,但实际上,这里的CP并不是纯粹的CP,内部通过AP完成了这种集群的同步机制。
随着互联网的发展,replicate的方案越来越少,sharding分片的方案会越来越多,而高可用的集群,则会采用 sharding + replicate的方式(1主2从),但万变不离其宗,无非都是通过类似的方式来达到同步的效果。
但业务上,我们不可能去写把业务中的表去打造成这种高可用的模式,所以,我们在业务上,会考虑把更多的同步改成异步,把CP改造成AP,把强一致性改成最终一致性。
比如:支付的场景,支付成功后,需要等待回调,因为回调的延时我们是无法控制的,因此一般的公司会用状态机去维护这个状态来重试,保证最终执行成功。
还有个例子,我们为了让业务支持高并发,会尽可能的把同步改造成异步,也就是说,除非是强依赖的前后调用,否则我都会用异步的方式解决,常用的异步有两种方式,mq和异步线程(目前可用hystrix来优雅的编写异步线程的事件)。
举一个实际业务上的例子,商品详情页,我们从业务上分析,商品详情页必要的属性是哪些,也就是说,没有这些属性,商品详情页根本没必要展示;那我列举一下:商品库存、商品价格这两个起码是必须的;而商品图片、名称、描述这些就算没有,只要我能保证用户下单成功,那它就不是强依赖因素,因此,我们会在商品详情页获取价格、库存,如果获取失败,直接抛异常交给上层捕捉;而商品图片、描述、名称这些,我们通过异步线程(hystrix)去并发去访问,设定1s的响应时间,也就是说,我只等1s,如果1s你还不给我,我就认为返回的是null。这样,就是一个非常高效的接口。
这样的业务场景其实非常有意思,值得我们去更多的思考,以后我会和大伙分享越来越多的这样的应用,另外这个文章缺图,我有点懒得画图,下次有机会我再补上。
网友评论