目录
AT模式(弥补了XA模型中资源锁定周期过长的缺陷)(高可用性)
限流
为什么要限流?
1.并发的确大(突发流量)
2.防止用户恶意刷接口
限流的实现方式:
Tomcat:可以设置最大连接数(适合单体项目)
- Nginx,漏桶算法
控制速率(突发流量)
控制并发连接数
网关,令牌桶算法
自定义拦截器
你们项目中有没有做过限流?怎么做的?
1,先来介绍业务,什么情况下去做限流,需要说明 QPS 具体多少
- 我们当时有一个活动,到了假期就会抢购优惠券,QPS 最高可以达到 2000,平时 10 - 50 之间,为了应对突发流量,需要做限流
- 常规限流,为了防止恶意攻击,保护系统正常运行,我们当时系统能够承受最大的 QPS 是多少(压测结果)
2,nginx 限流 - 控制速率(突发流量),使用的漏桶算法来实现过滤,让请求以固定的速率处理请求,可以应对突发流量
- 控制并发数,限制单个 ip 的链接数和并发链接的总数
3,网关限流 - 在 spring cloud gateway 中支持局部过滤器 RequestRateLimiter 来做限流,使用的是令牌桶算法
- 可以根据 ip 或路径进行限流,可以设置每秒填充平均速率,和令牌桶总容量
令牌桶和漏桶算法有什么区别?
原理
- 漏桶算法:可以看作是一个底部有漏洞的桶,无论请求以多快的速度进入桶内,漏桶都会以固定的速率将请求 “漏出” 进行处理。如果桶满了,后续进入的请求就会被丢弃。比如,一个漏桶每秒钟能处理 10 个请求 ,如果在某一秒钟内涌入了 30 个请求,那么除了这一秒正常处理的 10 个请求,另外 20 个请求会被丢弃。
- 令牌桶算法:系统会以恒定的速率向桶中放入令牌,每个请求在处理之前需要先从桶中获取一个令牌,如果桶中有足够的令牌,请求就能被处理;如果没有令牌,请求就需要等待或者被丢弃 。例如,令牌桶以每秒 10 个的速率生成令牌,桶的容量是 100 个,如果在某一时刻桶中有 20 个令牌,此时来了 30 个请求,那么其中 20 个请求可以立即获取到令牌并被处理,剩下 10 个请求则需要等待新的令牌生成。
流量处理特性
- 漏桶算法:能够强行限制数据的传输速率,使请求以均匀的速率被处理,所以它可以很好地平滑突发流量 ,但在面对突发流量时,无法利用系统的瞬间处理能力,可能会导致资源利用率不足。比如,在电商大促瞬间有大量抢购请求,漏桶只能按照固定速率处理,即使服务器还有处理能力,也无法及时处理更多请求。
- 令牌桶算法:在保持平均速率限制的同时,允许一定程度的突发流量,只要桶内有足够的令牌,就可以快速处理请求,充分利用系统资源。例如,平时系统处理请求速率是每秒 10 个,在促销活动时,由于之前积累了一定数量的令牌,短时间内可以处理更多请求。
分布式事务
Seata架构
Seata 事务管理中有三个重要的角色:
- TC (Transaction Coordinator) - 事务协调者:维护全局和分支事务的状态,协调全局事务提交或回滚。
- TM (Transaction Manager) - 事务管理器:定义全局事务的范围、开始全局事务、提交或回滚全局事务。
- RM (Resource Manager) - 资源管理器:管理分支事务处理的资源,与 TC 交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
XA模式
一、全局事务开启(TM 主导)
TM(事务管理器)作为全局事务的发起方,首先执行 1.1 开启全局事务 操作,标记一个分布式事务的开始。这一步是整个 XA 模式的起点,明确事务的边界,后续所有分支事务都将关联到这个全局事务中,为跨微服务的业务操作提供统一的事务上下文。
二、分支事务初始化(TM 调用 + RM 执行)
- TM 调用分支:TM 执行 1.2 调用分支 动作,触发微服务中的业务逻辑执行。此时,微服务内的 RM(资源管理器)开始介入分支事务处理,为后续注册和执行分支事务做准备。
- RM 注册分支事务:微服务中的 RM 执行 1.3 注册分支事务,主动向 TC(事务协调者)登记当前分支事务。这一步让 TC 感知到分支事务的存在,建立全局事务与分支事务的关联,TC 后续可通过该关联管理分支事务的状态。
- RM 执行业务 SQL:RM 内部执行 1.4 执行业务 SQL,在分支事务的上下文里处理具体业务逻辑(如数据库增删改操作 )。但与本地事务不同,XA 模式下这一步 仅执行 SQL 但不提交,为二阶段的统一提交 / 回滚预留控制入口,保证分布式事务的原子性。
- RM 报告事务状态:RM 完成业务 SQL 执行后,执行 1.5 报告事务状态,将分支事务的执行结果(成功或失败)反馈给 TC。TC 由此收集各分支事务的状态,为二阶段的决策提供依据。
三、全局事务二阶段决策(TC 主导)
- TC 检查分支事务状态:TC 执行 2.2 检查分支事务状态,汇总各 RM 报告的分支事务执行结果。这一步是 XA 模式的核心决策点,TC 需基于所有分支事务的状态,判断全局事务是提交还是回滚。
- TC 发起全局指令:根据分支事务状态,TC 执行 2.1 提交、回滚全局事务 操作:
- 若所有分支事务均成功,TC 向各 RM 发送 2.3 提交 指令,要求完成分支事务的最终提交,保证全局事务的一致性;
- 若任意分支事务失败,TC 向各 RM 发送 2.3 回滚 指令,要求撤销已执行的分支业务操作,避免数据不一致。
四、分支事务最终执行(RM 响应 TC 指令)
RM 接收 TC 下发的 2.3 提交 / 回滚 指令后,执行分支事务的最终操作:
- 若指令是提交,RM 会提交一阶段执行的 SQL,将业务操作持久化到数据库,完成分支事务;
- 若指令是回滚,RM 会回滚一阶段执行的 SQL,撤销未提交的业务操作,保证数据恢复到事务执行前的状态。
AT模式(弥补了XA模型中资源锁定周期过长的缺陷)(高可用性)
一、全局事务开启(TM 主导触发)
TM(事务管理器)执行 1.1 开启全局事务,标记分布式事务的起始,为后续分支事务划定统一的事务边界,让 TC(事务协调者)和 RM(资源管理器)感知全局事务上下文。
二、分支事务初始化与执行(RM 主导阶段一)
- TM 调用分支:TM 执行 1.2 调用分支,触发微服务内的业务逻辑执行,此时微服务中的 RM 开始处理分支事务,进入 AT 模式的核心阶段。
- RM 注册分支事务:RM 执行 1.3 注册分支事务,主动向 TC 登记当前分支事务,建立全局事务与分支事务的关联,使 TC 能够管理分支事务的状态。
- RM 记录 undo-log(数据快照):RM 在执行业务 SQL 前,会记录 更新前后的数据快照(undo-log),内容包含数据修改前的旧值、修改后的新值等。这是 AT 模式区别于 XA 模式的关键:通过快照实现 “柔性” 事务控制,避免长时间锁定资源。
- RM 执行业务 SQL 并提交:RM 执行 1.4 执行业务 SQL 并提交,直接完成本地事务的提交(与 XA 模式 “一阶段不提交” 不同 )。此时业务数据已落库,但由于记录了 undo-log,后续可通过回滚快照实现最终一致性,一阶段即可释放数据库锁,解决了 XA 模式资源锁定周期过长的问题。
- RM 报告事务状态:RM 执行 1.5 报告事务状态,将分支事务的执行结果(成功或失败)反馈给 TC,TC 由此收集各分支事务的状态,为二阶段决策提供依据。
三、全局事务二阶段决策(TC 主导)
- TC 检查分支事务状态:TC 执行 2.2 检查分支事务状态,汇总各 RM 报告的分支事务执行结果,判断全局事务的最终走向:
- 若所有分支事务均成功,TC 向各 RM 发送 2.3 提交 指令;
- 若任意分支事务失败,TC 向各 RM 发送 2.3 回滚 指令。
- TC 发起全局指令:TC 执行 2.1 提交、回滚全局事务 操作,根据分支事务状态,统一向 RM 下发提交或回滚的指令,驱动各分支事务完成最终的一致性保障。
四、分支事务最终处理(RM 响应 TC 指令)
场景 1:全局事务提交(TC 下发提交指令)
RM 接收 2.3 提交 指令后,执行 2.4 删除 undo-log,因为业务 SQL 已在一阶段提交,删除快照即可释放资源,标志分支事务彻底完成,全局事务达成最终一致。
场景 2:全局事务回滚(TC 下发回滚指令)
RM 接收 2.3 回滚 指令后,执行 2.4 恢复 log 数据,通过一阶段记录的 undo-log(数据快照),将业务数据回滚到修改前的状态,撤销一阶段的业务操作,保证全局事务的一致性。
TCC模式(高可用性,高耦合)
一、全局事务开启(TM 触发起点)
TM 执行 1.1 开启全局事务,标记分布式事务的起始,为后续跨微服务的分支事务提供统一的事务上下文,让 TC 和 RM 明确事务边界。
二、分支事务初始化(TM 调用 + RM 参与)
- TM 调用分支:TM 执行 1.2 调用分支,触发微服务内的业务逻辑,此时微服务中的 RM 开始处理分支事务,进入 TCC 模式的核心流程。
- RM 注册分支事务:RM 执行 1.3 注册分支事务,主动向 TC 登记当前分支事务,建立全局事务与分支事务的关联,使 TC 能够管理分支事务的状态。
- RM 报告事务状态:RM 在完成分支事务的 Try 阶段后,执行 1.5 报告事务状态,将 Try 阶段的执行结果(成功或失败)反馈给 TC,TC 由此收集各分支事务的状态。
三、TCC 三阶段之 Try(RM 主导)
RM 执行 1.4 资源预留(Try),这是 TCC 模式的核心阶段:
- 资源检测:检查业务操作所需的资源(如库存、余额等)是否充足;
- 资源预留:冻结或锁定资源(如扣减库存预留量、冻结账户金额 ),确保后续 Confirm 或 Cancel 阶段可操作。
- 关键约束:Try 阶段需保证 “幂等性”(重复调用不影响结果),且要为 Confirm/Cancel 阶段的执行做好准备。
四、全局事务二阶段决策(TC 主导)
- TC 检查分支事务状态:TC 执行 2.2 检查分支事务状态,汇总各 RM 报告的 Try 阶段结果,判断全局事务的最终走向:
- 若所有分支事务的 Try 均成功,TC 向各 RM 发送 2.3 提交 指令,触发 Confirm 阶段;
- 若任意分支事务的 Try 失败,TC 向各 RM 发送 2.3 回滚 指令,触发 Cancel 阶段。
- TC 发起全局指令:TC 执行 2.1 提交、回滚全局事务 操作,根据分支事务状态,统一向 RM 下发 Confirm 或 Cancel 指令,驱动各分支事务完成最终的一致性保障。
五、TCC 三阶段之 Confirm/Cancel(RM 执行)
场景 1:全局事务提交(TC 下发提交指令)
RM 执行 2.4 Confirm,此阶段需完成:
- 资源操作落定:将 Try 阶段预留的资源真正执行(如扣减实际库存、转账到账 );
- 幂等性保障:确保 Confirm 操作可重复执行(即使重试也不会重复扣减 / 增加资源 );
- 关键约束:Try 成功后,Confirm 必须能成功执行(否则需通过重试、补偿保证最终一致性 )。
场景 2:全局事务回滚(TC 下发回滚指令)
RM 执行 2.4 Cancel,此阶段需完成:
- 预留资源释放:撤销 Try 阶段的资源预留(如解冻库存、返还冻结金额 );
- 幂等性保障:确保 Cancel 操作可重复执行(即使重试也不会重复释放资源 );
- 作用:恢复业务数据到 Try 阶段前的状态,保证全局事务的一致性。
MQ分布式事务(高性能,实时性低)
你们采用哪种分布式事务解决方案?
- 简历上写的微服务,只要是发生了多个服务之间的写操作,都需要进行分布式事务控制
- 描述项目中采用的哪种方案(seata | MQ)
- seata 的 XA 模式,CP,需要互相等待各个分支事务提交,可以保证强一致性,性能差 银行业务
- seata 的 AT 模式,AP,底层使用 undo log 实现,性能好 互联网业务
- seata 的 TCC 模式,AP,性能较好,不过需要人工编码实现 银行业务
- MQ 模式实现分布式事务,在 A 服务写数据的时候,需要在同一个事务内发送消息到另外一个事务,异步,性能最好 互联网业务
分布式服务的接口幂等性如何设计?
token+redis
生成token 带token验证
分布式锁
回答
- 幂等:多次调用方法或者接口不会改变业务状态,可以保证重复调用的结果和单次调用的结果一致
- 如果是新增数据,可以使用数据库的唯一索引
- 如果是新增或修改数据
- 分布式锁,性能较低
- 使用 token+redis 来实现,性能较好
- 第一次请求,生成一个唯一 token 存入 redis,返回给前端
- 第二次请求,业务处理,携带之前的 token,到 redis 进行验证,如果存在,可以执行业务,删除 token;如果不存在,则直接返回,不处理业务