目录
单体项目
多个模块共享同一个 Tomcat,Tomcat 资源有限,当用户高并发访问同一个资源,其他模块会变得很卡(资源被占用完了)
事务一致性:同一个模块,直接使用 @Transactional 注解即可实现事务一致
微服务项目
不同微服务部署在不同的 Tomcat 中,原则上某一服务被高并发访问不会影响其他服务的访问,但是 服务之间会相互调用 一个服务延时较高 / 崩了也会影响到其他服务的业务
事务一致性:微服务之间相互调用,可能会出现数据不一致的问题,比如用户下单时会先保存订单再到数据库中扣减库存,数据库可能扣减失败 / 库存不足,但是订单数据已经保存了,出现数据不一致
一、雪崩问题
1. 雪崩:微服务调用链路中的某个服务故障,引起整个链路的所有微服务都不可用(微服务群崩溃)
2. 产生原因
- 微服务相互调用,服务提供者出现故障或阻塞
- 服务调用者没有做好异常处理,导致自身故障
- 调用链中的所有服务级联失败,导致整个集群故障
3. 解决问题的思路
- 尽量避免服务出现故障或阻塞
- 保证代码的健壮性
- 保证网络畅通
- 能应对较高的并发请求
- 服务调用者做好远程调用异常的后背方案(Fallback),避免故障扩散
以下介绍三种服务保护方案,这些服务保护统称为服务降级
服务降级:提供的服务下降了一个级别,没有之前完整 / 好 / 对请求做限制,服务体验下降
限制某一微服务,保护微服务集群
案例:
淘宝双十一期间关闭抽奖等边缘业务,将服务器资源让给核心的业务如秒杀下单支付等,提高微服务的并发能力
买鱼:平日买鱼摊主会将鱼杀号清理好交给顾客,节日期间买鱼的人特别多,来不及服务,直接将鱼拍晕给顾客,服务降级了
二、服务保护方案一:请求限流
1. 请求限流:限制访问接口的请求的并发量,避免服务因流量激增出现故障
2. 限流器:类似于漏斗,将大量的 / 高并发的请求缓慢均匀地放出,单机 QPS(每秒并发量) 由 xxx 降低到 xxx / 流量整形(陡峭变平缓)
三、服务保护方案二:线程隔离
线程隔离是在故障已经发生,如何避免扩散
请求限流是故障未发生,避免发生故障
1. 线程隔离
-
也叫舱壁模式,模拟船舱隔板的防水原理。将故障限制 / 隔离在一定的范围内,避免扩散
-
通过限定每个业务能使用的线程数量而将故障业务隔离,避免故障扩散
四、服务保护方案三:服务熔断
只做线程隔离还不够,线程还是占用着 CPU 和内存等资源,还在阻塞
1. 服务熔断:
-
由 断路器 统计请求的异常比例或慢调用比例,如果超出阈值则会熔断该业务,并拦截该接口的请求
-
熔断期间,所有请求快速失败,(业务失败时不再抛出异常)而是走 fallback 逻辑(兜底方案)
2. 熔断:可以看作电器和电路的保险丝,电路符合较大,电流较大时就会烧断保险丝,不再有电流通过,保护电器
五、服务保护技术——Sentinel
1. Sentinel 简介
- 阿里开源的 流量控制组件 sentinel(哨兵)
- 官网:home | Sentinel (sentinelguard.io)
2. 两个核心
- 核心库依赖:Sentinel 客户端
- Sentinel 控制台(图形化界面)服务
- 实时监控:监控微服务内部接口运行情况,形成统计数据
- 配置限流规则、熔断规则等
3. 实现步骤
- 控制台服务
- 搭建控制台服务:下载官方的 jar 包 / 引入 Maven 依赖
- 运行 jar 包:通过控制台命令启动
其他方式:将 jar 包构建成 java 镜像放入容器,设置开机自启,虚拟机启动就会自动启动控制台服务
- 访问控制台:访问 jar 包启动时的地址和端口(账号:sentinel 密码:sentinel)
- 微服务整合 Sentinel
- 引入依赖:spring-cloud-starter-alibaba-sentinel
- 配置 application.yaml 文件,添加 Sentinel 控制台的地址
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8090 # 控制台地址
注意❗Sentinel 是监控微服务运行的,一开始微服务没有被访问不会被监控到
4. 簇点链路
1. 簇点链路:
-
单机调用链路,一次请求进入服务后经过的每一个被 Sentinel 监控的资源链,默认 Sentinel 会监控 SpringMVC 的每一个 Endpoint(HTTP 请求 / Controller)
-
限流、熔断等保护都是针对簇点链路中的资源(簇点)进行设置的
-
资源名默认是请求路径(簇点)
簇点资源名称重复:Restful 风格的 API 请求路径一般都相同,导致簇点资源名称重复
解决方法:通过配置把 请求方式 + 请求路径 作为簇点资源名
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8090 # 控制台地址
http-method-specify: true # 开启请求方式前缀