Spring Cloud 常见业务问题
1. 你们项目中有没有做过限流?怎么做的?
tip:这里的限流指的是对接口限流
为什么要限流:
- 并发量确实很大(某个时间点的突发流量)
- 防止用户恶意刷接口
限流的实现方式:
Tomcat:可以设置最大连接数
Nginx 的漏桶算法
网关的令牌桶算法
自定义拦截器
1.1 Nginx 限流
控制速率(突发流量):
控制并发连接数:
1.2 网关限流
同时设置 IP 和 路径限流,指的是 IP 的请求,对指定路径的请求都被限流,是取并集;
1.3 回答
- 介绍实际业务场景,说明一下 QPS 具体多少
- QPS(Query Per Second):每秒请求数,就是说服务器在一秒的时间内处理了多少个请求。
- 例如,我们当时有一个活动,到了假期就会抢购优惠券,QPS 达到了 2k,平时都是 10 - 50,为了应对突发流量,需要做限流;
- 常规限流,为了防止恶意攻击,保护系统正常运行,我们当时系统能够承受最大的 QPS 是 3k (具体根据压测结果)
- 常见的限流算法有两种:
- nginx 漏桶算法 :
- 控制速率(突发流量),使用漏桶算法来实现过滤,让请求以固定的速率处理请求;
- 控制并发量,限制单个 IP 同时的连接数和并发连接的总数;
- 网关令牌桶算法:
- 在 Spring Cloud Gateway 中支持局部 过滤器 RequestRateLimiter 来做限流,使用的是令牌桶算法;
- 可以根据 IP 或路径进行限流,可以设置每秒填充平均速率和令牌桶总容量;
- nginx 漏桶算法 :
2. 解释一下 CAP 和 BASE
CAP 定理和 BASE 理论的存在是为了:
- 分布式事务方案的指导
- 分布式系统设置的方向
- 根据业务指导使用正确的技术选择
2.1 CAP 定理
- 数据一致性我觉得更广泛的理解是,数据符合预期;
很多情况下 CA 不仅仅是因为分区导致不能同时实现的,例如分布式的一些并发问题;
- C 与 A 无法同时满足,分区只是其中一种较大的原因;
为分区的现象不能完全避免,所以一个分布式系统的大前提是先搞好 P, C 和 A 才有用武之地;
但是分区一旦出现,C 与 A 无法同时满足;
2.2 BASE 理论
BASE 理论是对 CAP 的一种解决思路(“退而求其次”),包含三个概念:
- 可以理解为 AP 的最佳实践 => 最终一致思想;
2.3 回答
- CAP 定理(一致性、可用性、分区容错性)
- 分布式系统节点通过网络连接,一定会出现分区问题(P)
- 当分区出现时,系统的一致性(C)和可用性(A)就无法同时满足
- BASE 理论
- 基本可用
- 软状态
- 最终一致
- 解决分布式事务的思想和模型:
- 最终一致思想:各分支事务分别执行并提交,如果有不一致的情况,再想办法恢复数据(AP)
- 强一致思想:各分支事务执行完业务不要提交,等待彼此结果。而后统一提交或回滚(CP)
3. 你们采用哪种分布式事务解决方案(了解)
首先介绍项目场景用到哪种,咋用的;
常见的有两种:
- Seata 框架(XA、AT、TCC)
- MQ
3.1 Seata 框架(XA、AT、TCC)
3.2 MQ
3.3 回答
4. 分布式服务的接口幂等性如何设计?
幂等:多次调用方法或者接口,不会改变业务状态,可以保证重复调用的结果和单次调用的结果一致。
需要幂等的场景:
- 用户重复点击(接口响应慢、网络波动)
- MQ 消息重复
- 应用使用失败或者超时重试
需要幂等的场景往往是同一个用户非主观想要去反复请求的,并且根据业务的预期效果判断幂等需不需要维护,是否是并发问题
与并发问题本质不同;
例如,提交淘宝订单:
这种“新增”的操作,一定不是幂等的,如果是很需要保证幂等性的场景下,则需要去维护一下;
4.1 Token + Redis
打开页面时就是第一次请求,获取 Token
4.2 分布式锁
- 图中不设置等待时间,代表快速失败;
- 当然,根据业务不同,你可以灵活的去控制
- 比如一个定制微信小程序码的接口,第一次请求时间比较长,需要 2 秒才能响应,但是第一次请求会缓存起来,之后就只需要几毫秒就能响应了,但是用户以为没点到,就多点了几次,导致发了很多个请求,生成了 N 个小程序码;对于这种情况而这里我们就可以用分布式锁,让第一次获得锁生成小程序码,然后缓存起来,释放锁后,其他几次请求都走缓存快速响应相同的结果;
- 不必较真是不是幂等啥的,为了达到业务的预期,想尽办法吧!
对于单体架构的幂等性问题也同样适用,因为分布式锁可以很灵活控制锁的粒度;
4.3 回答
- 幂等:多次调用方法或者接口不会改变业务状态,可以**-**
- 如果是新增数据,可以使用数据库的唯一索引;
- 如果是新增或者修改数据
- 分布式锁,性能较低;
- 使用 Token + Redis 来实现,性能较好;
- 第一次请求,生成一个唯一 Token 存入 Redis,返回给前端;
- 第二次请求,业务处理,携带之前的 Token,到 Redis 进行验证,如果存在就执行业务,删除 Token;如果不存在,就直接返回,不处理业务;
5. 你们项目使用了什么分布式任务调度
首先还是描述一下什么场景有任务调度;
- 流行的分布式任务调度系统是 xxl-job;
xxl-job 解决的问题?
- 解决集群任务的重复执行问题;
- cron 表达啥定义灵活;
- 定时任务失败了,重试与统计;
- 任务量大,可分片执行;
xxl-job 路由策略有哪些?
- xxl-job 提供了很多的路由策略,我们平时用的较多的就是:轮询、故障转移、分片广播…
xxl-job 任务执行失败怎么解决?
- 路由策略选择故障转移,适用健康的实例来执行任务;
- 设置重试次数;
- 查看日志 + 邮件告警来通知相关的负责人解决;
邮箱告警:
在 xxl-job 里面配置好邮箱信息:
如果有大数据量的任务同时都需要执行,怎么解决?
如果是一个大数据任务还好,可能让某个执行器节点被占据较长一段时间,除了是串行执行的速度比较慢,但是其他节点仍然可以继续调度任务
而如果是多个大数据任务,则可能导致占据的节点太多了,影响其他中小数据量的任务执行;
执行器集群部署时,任务路由策略选中 分片广播 情况下,一次任务调度将会被广播触发对应集群中所有执行器执行一次任务;
- 对于需要处理的大数据量任务,可以将任务分片成多个小任务,每个小任务只处理部分数据或处理一个子任务,对任务分片时,刻意的避免分片之间的依赖;
- 然后将这些小任务分配给执行器集群中的不同节点执行,以实现任务的并行处理;
- 这样可以降低单个任务的处理压力,提高整个任务的执行速度;
避免大数据量任务的执行占据了某个节点太久,子任务被执行后,可以去调度其他的任务,再执行大数据量任务的其他子任务;
回答:
- 让多个实例一块去执行(先部署集群),路由策略选择分片广播;
- 在任务执行的代码中可以获取分片
- 总量和当前分片,按照取模的方式分摊到各个实例执行;