文章目录
- 1、分布式系统
- 2、CAP定理
- 3、Base理论
- 4、分布式事务的解决方案:Seata
- 4.1 Seata的XA模式
- 4.2 Seata的AT模式
- 4.3 Seata的TCC模式
- 5、分布式事务的解决方案:MQ
- 6、分布式系统下,接口的幂等性
- 6.1 数据库唯一索引
- 6.2 token + redis
- 6.3 分布式锁
- 7、分布式任务调度xxl-job
- 7.1 路由策略
- 7.2 任务执行失败的处理
- 7.3 大数据量任务同时执行--分片广播
- 8、面试
1、分布式系统
简单说就是:一个活儿可以被多个人处理(一个请求过来,有多个节点都有能力处理它并响应),因此,需要考虑数据的一致性
而分布式系统中的多个节点,可以是多台物理机、多台虚拟机、多个容器。分布式系统的引入,提高了系统的:
- 可伸缩性(业务高峰期多起几个实例放节点上)
- 可靠性(多个节点可以干活儿,挂掉一台服务器也问题不大)
- 性能(并发能力变为n倍,n为节点数)
最后,加节点,是多了个干活儿的人,提到的是并发上限,单个接口,响应该几秒还是几秒,因为处理某个接口的这个活儿,你交给哪个人去干,都是那个耗时。
2、CAP定理
- Consistency:一致性
- Availability:可用性
- Partition tolerance:分区容错性
CAP定理即:布式系统无法同时满足这三个指标
一致性,即用户访问分布式系统的任意节点,得到的数据必须一致。一个活儿,多个人都可以处理,但你问甲的结果和问乙的结果必须一样
可用性,即用户访问集群中的任意健康节点,必须得到响应,不能超时或者拒绝。
分区容错,即集群出现分区时,整个系统也要持续对外提供服务。
分区容错性,背景是:因网络故障或其他原因,导致分布式系统的部分节点和其他节点失去了联系,形成了独立分区
此时,客户端往节点node02写入数据v1,而node02只能同步给node01,node03数据还是旧的,违背了一致性。反之,如果想要数据一致,那就让分区2的节点node03别干活儿了,penging到网络恢复,但这违背了可用性。
结论:
分布式系统节点之间肯定是需要网络连接的,分区(P)是必然存在的,因此,而分区一旦出现,如上分析,一致性和可用性就不可能同时满足。因此,CA是不可能的
- 如果保证访问的高可用性A,可以持续对外提供服务,但不能保证数据的强一致性 ⇒
AP
- 如果保证访问的数据强一致性C,就要放弃高可用性 ⇒
CP
3、Base理论
要么追求CP,要么追求AP,但也不是非0即1。追求了CP,仍然有数据的一致性,不过不再是强一致性,而是最终一致罢了。⇒ Base理论:
- Basically Available(基本可用):分布式系统在出现故障时,允许损失部分可用性,即保证核心可用
- Soft state(软状态):在一定时间内,允许出现中间状态,比如临时的不一致状态
- Eventually Consistent(最终一致性):虽然无法保证强一致性,但是在软状态结束后,最终达到数据一致
以上面的下单业务为例,下单后,需要做订单数据生成、账户扣款、库存余量维护。数据分布在不同的节点上,需要跨越多个节点或服务进行数据操作和事务处理(分布式事务)。此时就有两种选择:
最终一致
:各个分支事务(订单服务、账户服务、库存服务各自对应一个分支事务)分别执行并提交,如果哪一个分支事务执行失败,则需要恢复其他已提交的分支事务的数据(之前insert的就delete)。如此,数据最终一致,但会出现一个临时状态,也就是Base理论里所说的软状态,即数据不一致,订单服务库里有订单数据,但库存服务的库里数据未减少。 ⇒AP
- 强一致:各个分支事务执行完后不要提交,等待彼此的结果,统一提交或回滚,如此,数据强一致,但分支事务等待其他分支时,处于弱可用状态 ⇒
CP
4、分布式事务的解决方案:Seata
微服务架构下,多个微服务之间,只是做查询,那没啥好提事务的,但只要一个业务发生了多个微服务的写操作,如上面说的下单,就要进行分布式事务控制。解决方案:
- Seata
- MQ
Seata架构:
包括三个角色:
- TC(Transaction Coordinator):事务协调者,维护全局和分支事务的状态,协调全局事务提交或回滚
- TM (Transaction Manager): 事务管理器,定义全局事务的范围、开始全局事务、提交或回滚全局事务
- RM(Resource Manager):资源管理器,可以认为是每一个微服务的节点,他们分别对应一个分支事务
4.1 Seata的XA模式
分支事务各自执行业务SQL后,不提交分支事务,等待TC检查各个分支事务,如果各个分支事务的SQL执行都没报错,则通知分支事务一起提交事务,反之,通知各个分支事务一起回滚事务。体现的是CP
,即保证的是数据强一致性
XA模式缺陷是:各个分支事务之间要等待,等待期间,有资源锁定(业务SQL执行对应的数据被锁定,其他线程无法访问)
4.2 Seata的AT模式
和XA不同,AT模式下,各个分支事务会执行SQL并提交事务,但同时每个分支事务也都记录了undo-log日志。提交事务后,各个分支事务向TC报告自己的事务状态到TC,即告诉TC,自己的SQL执行成功没有,都成功,则删除undo-log日志,有一个失败,则根据undo-log把其余分支事务的数据退回去。
AT模式,体现的是AP
,只要最终一致性,不要强一致
4.3 Seata的TCC模式
TCC模式即,Try、Confirm、cancel。比如还是下单,买本书100元,订单服务对应的分支事务A,进行Try资源预留,即检查下你的余额有没有 > 100,有则冻结100块。库存服务对应的分支事务B,进行Try资源预留,即检查库存剩余数量是否 > 1。Try后,各个分支事务向TC报告事务状态,如果都成功,则进行Confirm,提交全局事务。反之,执行Cancel,释放预留资源。
缺点是Try的部分得自己代码实现。
5、分布式事务的解决方案:MQ
比如向借呗申请借钱,借呗系统资质审核通过后,支付宝系统余额才能增加。但借呗和支付宝在两个不同的系统,还不是一个系统的两个微服务。此时,可用MQ实现:
用户申请借钱,资质审核通过后,借呗系统落库借款单并给MQ发消息(这两步,借呗在自己的库里加事务去控制同成功、同失败)。支付宝系统监听MQ,消费,给对应的用户增加余额。这样,数据的强一致性最弱,也即"5分钟内到账
"。
最后,分布式事务各个方案的使用场景:
6、分布式系统下,接口的幂等性
幂等性:即多次调用一个接口,和单次调用一个接口,结果都一致,不会改变业务状态。 需要考虑幂等的场景如:用户重复点击(网络波动)。Restful API下的接口:
PUT不一定幂等:
//幂等
update t item set money= 500 where id = 1;
//不幂等
update t item set money = money + 500 where id = 1;
关于接口幂等性的实现方式:
6.1 数据库唯一索引
确保列或列组合的数值唯一性的索引,如此,插入数据时,多次调用就会报错:
这样只能处理新增的幂等性,修改的幂等性无法保证
6.2 token + redis
- 第一次请求,生成一个唯一 token 存入redis ,返回给前端
- 第二次请求,业务处理,携带之前的token,到redis 进行验证,如果存在,可以执行业务,删除token。如果不存在,则直接返回,不处理业务
6.3 分布式锁
如下,防止重复支付,用支付ID作为分布式锁的key,防止某一笔订单被重复支付
7、分布式任务调度xxl-job
xxl-job的优势:
- 解决集群任务的重复执行问题
- cron 表达式定义灵活,不再硬编码到代码中
- 定时任务失败了,重试和统计
- 任务量大,分片执行
7.1 路由策略
每个任务交给哪个节点(或者job服务的哪个pod)去干:
- First:固定选择第一个实例
- Last:固定选择最后一个实例
- Round:轮询
- Random:随机
- Least_Frequently_Used:最不经常使用的,使用频率最低的
- Least_Recently_Used:最近最久未使用,最久没被使用的
- FailOver:故障转移,按心跳检测,第一个心跳检测成功的
- BusyOver:忙碌转移,按空闲检测,第一个空闲检测成功的
- Sharding_Broadcast:分片广播
7.2 任务执行失败的处理
设置路由策略为故障转移 + 设置失败重试次数
重试后也可能失败,此时可查看日志,
以及设置邮件告警:页面上配置的是运维的邮箱
最后,部署xxl-job时,要配置下邮件发送者的信息,比如公司邮箱
7.3 大数据量任务同时执行–分片广播
分片广播的路由策略下,将一个任务分片执行并发到多个执行器上
在任务执行的代码中可以获取分片总数和当前分片,按照取模的方式分摊到各个实例执行:
8、面试