(六)Spring Cloud Alibaba 2023.x:Sentinel 流量控制与熔断限流实现
目录
前言
准备
下载sentinel控制台
项目集成
引入依赖
配置yml文件
限流控制
Sentinel注解
前言
在微服务架构中,流量控制组件至关重要,它是保障系统稳定性与高可用性的核心手段之一 。Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量控制、流量路由、熔断降级、系统自适应保护等多个维度来帮助用户保障微服务的稳定性。
准备
- jdk17+
- maven3.9.4+
- idea2023
- spring cloud: 2023.0.1.0
- spring cloud alibaba: 2023.0.1
源码获取:GitHub - RemainderTime/spring-cloud-alibaba-base-demo: 基于spring cloud alibaba生态快速构建微服务脚手架
下载sentinel控制台
本地运行sentinel控制台管理限流接口
本篇使用的版本:1.8.8
官方下载地址:Releases · alibaba/Sentinel
百度网盘:百度网盘 请输入提取码 提取码: 92h6
下载到本地就是一个jar包
在当前包文件夹中执行运行命令。端口号可自行更改
java -Dserver.port=8089 -Dcsp.sentinel.dashboard.server=localhost:8089 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.8.jar
启动成功访问http://127.0.0.1:8089/ 默认账号密码:sentinel
包含了sentinel本身的服务,已经博主已经配置启动完成的消费者生产者服务
项目集成
根据前面的博文,目前我们已经创建了三个微服务
引入依赖
每个服务都可能用到sentinel做限流,所以我们在父级pom.xml文件中引入sentinel依赖
<!-- 分布式限流降级组件 sentinel-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- 引入Transport 模块与 Sentinel 控制台进行通信 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.8.8</version>
</dependency>
配置yml文件
对消费者和生产者的yml文件配置sentinel
本篇着重是对常用接口和方法进行流量控制,对于网关路由限流不是本篇重点,所以不配置网关服务的sentinel。
spring:
application:
name: http-cloud-producer
cloud:
sentinel: #流量控制中心
transport:
dashboard: localhost:8089 # sentinel-dashboard地址
port: 8721
eager: true
filter:
enabled: true
注意!!!
8721表示的是当前服务中Sentinel客户端与sentinel控制台通信的端口,如果存在多个服务使用sentinel,那么每个服务的端口不能重复。如果只有一台服务使用sentinel,不设置端口默认是8719,但是进入sentinel控制台我们会发现,控制台本身就将8719端口占用了。
所以我们自己的服务如果不指定端口,sentinel会按照启动的先后顺序在8719基础上+1来分配端口。
限流控制
首先启动sentinel控制台,再启动依次启动项目服务后
在sentinel控制台中,我们发现项目服务中都是白板什么也没有。
那是因为我们目前什么请求都没有操作,所以sentinel没有监听到任何数据。
请求上一篇为了验证seata组件实现的下单接口(因为两个服务的接口都会被调用)
回到sentinel控制台我们会看到生产者和消费者服务数据都有了
通过控制台的限流按钮,对相关接口进行限流操作
将阀值设置为0,再次请求下单接口,就会返回限流提示
Sentinel注解
sentinel提供了一个注解@SentinelResource 可以加到接口或者方法上特殊处理
@RestController
public class FeignController {
@Autowired
private SentinelService sentinelService;
/**
* 使用sentinel 限流熔断注解并集合使用feign远程调用
* @return
*/
@GetMapping(value = "/sentinelOrFeign")
public String sentinelOrFeign() {
return sentinelService.sentinelOrFeign();
}
/**
* 使用sentinel 限流熔断注解 本地调用
* @return
*/
@GetMapping(value = "/sentinelLocal")
public String sentinelLocal() {
return sentinelService.sentinelLocal();
}
}
@Service
public class SentinelService {
@Autowired
private FeignService feignService;
@SentinelResource(value = "sentinelOrFeign", fallback = "fallbackHandler", fallbackClass = SentinelExceptionUtil.class,
blockHandler = "blockExHandler", blockHandlerClass = SentinelExceptionUtil.class)
public String sentinelOrFeign(){
return feignService.feignInfo01();
}
@SentinelResource(value = "sentinelLocal", fallback = "fallbackHandler", fallbackClass = SentinelExceptionUtil.class,
blockHandler = "blockExHandler", blockHandlerClass = SentinelExceptionUtil.class)
public String sentinelLocal(){
// throw new RuntimeException("测试sentinel本地调用异常捕获");
return "sentinel本地调用成功";
}
}
注解属性说明:
value: 自定义限流名称,不自定义就是默认接口或方法名。
blockHandler : 该方法或接口触发限流后需要特殊处理的方法名。
blockHandlerClass : 方法实现的类class。
fallback : 该方法或接口除了限流异常外的其他异常触发后处理的方法名。
fallbackClass : 方法实现的类class。
自定义处理类 SentinelExceptionUtil.class 实现
public class SentinelExceptionUtil {
/**
* Sentinel 规则的 流控、熔断、热点参数限流 等被触发时调用。优先级高于 fallback
* @param ex
* @return
*/
public static String blockExHandler(BlockException ex) {
ex.printStackTrace();
return "Sentinel 规则的 流控、熔断、热点参数限流 等被触发:" + ex.getMessage();
}
/**
* 业务异常(如运行时异常)或其他未被 Sentinel 规则拦截的异常触发。
* @param ex
* @return
*/
public static String fallbackHandler(Throwable ex) {
ex.printStackTrace();
return "业务异常或其他未被 Sentinel 规则拦截的异常触发: " + ex.getMessage();
}
}
同样对上面定义的接口设置限流阀值为0,请求返回了我们处理后的内容
注意!!!
上一篇使用了seata作为分布式事务,使用注解@GlobalTransactional。
如果当前方法上使用了分布式事务,那么不能对该方法进行限流控制或者是加@SentinelResource特殊处理,这样会使分布式事务失效,以及这个分布式事务涉及到的被调用方的接口也不能限制(实测避坑)。如果一定要进行限流,可以对调用该方法的接口进行限流处理是没有问题的。
至此Spring Cloud alibaba集成Sentinel实现熔断限流完成了