CAP简介
CAP定理是分布式系统中的基本理论之一,其中
Consistency(一致性):一致性指的是所有节点在同一时间看到相同的数据。在分布式系统中,保持数据的一致性是非常重要的,因为不同节点可能并不总是同时收到更新。在 Nacos 中,一致性体现在服务注册和配置管理方面。Nacos 使用了 Raft 一致性算法来确保集群中的数据一致性。当一个新的节点加入集群,或者节点发生故障时,Raft 算法能够确保数据仍然一致。
Availability(可用性):可用性指的是每个请求都能在有限的时间内收到响应,不管系统中的部分节点是否故障。在分布式系统中,保持高可用性意味着要确保系统在遇到故障时仍然能够提供服务。Nacos 的集群架构通过多节点部署和故障自动转移来保持高可用性。当节点故障时,其他节点能够继续提供服务。
Partition Tolerance(分区容错性):分区容错性指的是系统中的一些节点之间的通信可能会失败,即节点之间的连接可能会中断,但系统仍然可以继续工作。在分布式系统中,网络分区是无法避免的,因此需要保证系统在分区发生时依然能够正常工作。Nacos 的集群架构通过 Raft 算法来保证分区容错性。Raft 算法在节点故障或网络分区发生时,能够确保集群继续正常运行。
在一个分布式统统中,没办法同时保证三个特性,在某些特定的业务场景下,需要做出牺牲,Nacos支持两种模式。
Nacos的CAP
1、AP模式
Nacos的默认模式,临时实例采用的模式
对于可用性比较高的场景,例如:网站、在线游戏等,可以选择使用AP模式,这种模式下,Nacos会优先保证服务的可用性,然后尽可能的保证服务数据的一致性,减少对业务的影响。对于Nacos的注册中心而言,应该是AP模式,保证服务的高可用,实现数据的最终一致性,这个样可以减少注册中心的压力,对于业务系统而言,在一致性方面,框架一般都会提供服务的容错性和重试机制,避免数据不一致的问题。

2、CP模式
永久实例采用的模式,这意味着即使实例宕机,Nacos服务列表中的实例信息也不会被清除。
对于一致性要求比较高的场景,如:金融、支付等场景,这些场景下,为了保证数据的一致性,会对服务进行隔离和恢复,但是这会导致一些服务的不可用,牺牲服务的可用性。
要设置永久实例,你需要在application.properties或application.yml文件中进行配置。
spring:
cloud:
nacos:
discovery:
ephemeral: false # 设置ephemeral为false即表示该实例为永久实例。
服务掉线,不会清除实例信息

分布式TX-LCN/Seata:CAP理论
tx-lcn分布式事务:CP
代理的方案实现,事务是交给LCN做代理的,做统管理的
例子场景
AB两个业务,A订单,B账户 A ->B A下单,并调用B服务扣款
接口进入A之前,向lcn申请一个全局事务id,并A事务挂起(待提交)
A执行完毕,调用B,并携带全局事务ID,进入B的时候,也会向LCN提交自己的全局事务ID,形成一个事务组,LCN会将AB两个事务打包成一个组
B执行完毕,A根据业务是否报错,向LCN提交最终状态(成功,失败),LCN根据A的最终状态,觉得整个事务组是提交,还是回滚:轮询事务组,通知的方式:netty长连接通知
所以lcn自己本身没有事务功能,只起到事务管理/通知的功能,其中的一些操作:A申请全局事务ID,B提交自己的事务ID,A提交最终结果,LCN轮询通知事务结果等,都是LCN自己的完成的,不需要我们业务去参与
,轮询通知是LCN内部的业务,自己实现原子性
两个很重要的模块:TM 和 TC
C:一致性,因为在处理过程中,AB的事务,都是挂起状态,没有提交,LCN根据A最终状态,才去真正的提交或者回滚,所以是个整体,AB数据是一致的
但是会导致死锁
最终的业务结果,严重依赖A的最终状态,LCN在等待A的最终状态,针对这个业务的全局事务,是堵塞在这里的,等A的结果,这个时候,如果A重启了,或者服务挂了,那么LCN等待不到自己想要的资源,就会进入一个死锁状态
LCN的其他两种事务方式:
lcn/TCC try confirm cancel
lcn/2pc/3pc
seata分布式事务:AP (ali)
A可用性,就是服务只要不挂,什么时候调用,都能得到响应,不会报错(除了业务自己的异常)
前置镜像:事务执行前的数据状态
后置镜像:事务执行后的数据状态
需要在每个参与事务的数据库中,创建一个seata的日志表:undo_log(表名可以任意)
AB两个业务服务,在事务执行前(sql dml),会将数据先保存到seata的业务表(undo_log)中,并且每个事务执行之后,结果也会保存到undo_log中
当所有事务都执行完毕,那么就结束,并删除undo_log表
当A成功,B失败的时候,那么A的数据,会根据undo_log中的前置镜像数据做回滚
这些操作,都是AB自己的数据库中undo_log自己实现的,不存在互相竞争资源的问题,
脏读:一个事务,读取到了另一个事务未提交的数据
A执行成功,在执行B的过程中,A数据已经落库了,这个时候如果有其他业务读取A修改的数据的话,就产生了脏读
其他分布式CAP场景:
nacos:AP(临时实例)/CP(永久实例)永久实例服务下线,会导致其他业务报错,服务不会下线
hmily分布式事务TCC:金融级别的分布式事务,AP,导致脏读,但是自己加了很多锁进去,保证一致性,但是会影响效率,去中心化的,侵入业务的,实现比较繁琐