SpringCloudAlibaba 学习 --->>> Sentinel 学习 -->> 使用Sentinel
使用Sentinel
首先需要一个模块注册到nacos并且引入sentinel场景依赖并做好有关配置
1、初步使用 Sentinel
1、创建模块
创建一个名字好认的模块
2、改pom
需要引入sentinel、nacos场景依赖,这个场景依赖坐标在官网也能找到
<dependencies>
<!--SpringCloud ailibaba nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--SpringCloud ailibaba sentinel-datasource-nacos 后续做持久化用到-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<!--SpringCloud ailibaba sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- SpringBoot整合Web组件+actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--日常通用jar包配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>4.6.3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
3、写yaml
server:
port: 9010
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
#Nacos服务注册中心地址
server-addr: localhost:8848
sentinel:
transport:
#配置Sentinel dashboard地址
dashboard: localhost:8080
#默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
port: 8719
# 持久化配置
datasource:
ds1:
nacos:
server-addr: localhost:8848
dataId: cloudalibaba-sentinel-service
groupId: DEFAULT_GROUP
data-type: json
rule-type: flow
# 指标监控
management:
endpoints:
web:
exposure:
include: '*'
4、主启动类
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class SentinelService9010Application {
public static void main(String[] args) {
SpringApplication.run(SentinelService9010Application.class, args);
}
}
5、业务类
需要有controller来进行测试sentinel的功能配置
@RestController
@Slf4j
public class SentinelService9010Controller {
@Autowired
Sentinel9010Service service;
@GetMapping(value = "/sentinel/get/{id}")
public String getMessage(@PathVariable("id") Integer id){
return service.getMessage(id);
}
@GetMapping("/testA")
public String testA(){
log.info("********方法被调用");
return "************testA";
}
@GetMapping("/testB")
public String testB(){
return "**************testB";
}
@GetMapping("/testC")
public String testC()
{
//暂停几秒钟线程
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
log.info("testC 测试RT");
return "------testC";
}
@GetMapping("/testD")
public String testD()
{
log.info("testD 测试RT");
int age = 10/0;
return "------testD";
}
/**
* 使用注解 @SentinelResource 声明请求处理时超出处理限制的 fallbackMethod
* @param p1
* @param p2
* @return
*/
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey",blockHandler = "dealHandler_testHotKey")
public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
@RequestParam(value = "p2",required = false) String p2){
// int i = 10 / 0;
return "------testHotKey";
}
public CommonResult dealHandler_testHotKey(String p1, String p2, BlockException exception)
{
return new CommonResult(555,"参数值不是dd就只能一秒请求一次");
}
/**
* @SentinelResource 指定处理限流返回结果的处理方法
* 属性 value 就是在 sentinel 中添加热点规则的对象
* 属性 blockHandlerClass 值就是当前 requestHandle 处理请求限流时调用返回结果方法所在类
* 属性 blockHandler 值就是请求被限流时都要调用的方法名
* 此过程建议 CV
* @return 限流报文
*/
@GetMapping("/byResource")
@SentinelResource(value = "byResource",
blockHandlerClass = MyHandler.class,
blockHandler = "handleException")
public CommonResult byResource() {
return new CommonResult(200,"按资源名称限流测试OK",new Payment(2020L,"serial001"));
}
}
6、测试
首先保证 nacos、sentinel启动并且可以访问,然后启动项目注册到注册中心,此时去sentinel控制台界面查看模块信息发现是查看不到的,需要调动模块功能后才可以查看并配置模块相关配置
发送请求 http://localhost:9010/testA 调用模功能,然后再次刷新查看sentinel管理配置界面,就能看见 sentinel 控制台里面关于模块的各种资源规则设置界面
在sentinel中模块名就是模块的配置文件中设置的模块名
在sentinel控制台中设置各种规则可以在规则详细设置分项中设置,也可以直接在 簇点链路 中针对资源添加规则

-0-
2、添加流控规则
对模块中的资源添加流控规则,设置资源访问规则,点击资源后面跟着的按钮或者去流控规则里面添加对应资源名的流控规则都可以

--0--
针对上图的功能介绍和功能点的解释:GitHub地址 里面解释了相关名词以及流控出现的结果
规则介绍
由上图可以发现主要是针对访问资源的 QPS 和 线程数 设置流控规则,其中线程数只能设置流控模式不能设置流控效果只能直接失败
资源名是一个唯一值,就像 id 这种区别标识符一样,默认是请求映射路径。后面也可以设置
针对来源是指调用当前资源的服务模块名【即针对服务调用者限流,熟悉的百度网盘】,默认 default 意思就是不区分来源
QPS 就是一秒内访问当前资源的请求,单机阈值就是指请求数
流控模式
- 直接:当访问的请求数或线程数达到上面设置要求就会直接产生指定的流控效果
- 关联:当访问的请求数或线程数达到上面设置要求就会影响他关联的资源产生指定的流控效果
- 链路:当访问的请求数或线程数达到上面设置要求就会对指定资源入口产生指定的流控效果
流控效果
- 快速失败:看名字就知道,当访问的请求数或线程数达到上面设置要求就会直接拒绝访问并返回提示信息
- Warm Up:意思是热身,热加载,也可以是预加载,当访问的请求数或线程数达到上面设置要求就会在指定时长后允许访问指定的QPS或线程数
- 这里需要引入一个概念 coldFactor 冷因素 :它默认值是 3
- 现在设置了 QPS 值为30,流控效果是Warm Up,那么实际上允许访问资源的QPS是
threshold / 310个 ,如果超过了10个的话,就会先拒绝请求返回提示信息,然后在指定时间内把QPS值上升到30个
- 排队等待:当访问的请求数或线程数达到上面设置要求就会让请求等待指定时长后在对其处理,这个的话可能会使有些功能报超时异常,openFeign 默认就等待一秒,没有结果直接出错,这个要有熟练度
添加流控规则
此时要往模块资源上添加流控规则,可以选择在簇点链路或者流控规则栏里面为指定资源名资源添加流控规则
设置直接失败限流规则

上图表示当一秒内调用资源名的请求超过一个,就直接限流并返回默认提示信息
可以通过手动刷新请求测试
设置预加载限流规则

上图表示设置资源testA正常情况下允许的QPS为 10/3 即3个请求,如果超过了这个范围就会限流,然后在 5 秒后将资源testA的QPS提升至10个
可以通过手动刷新请求测试
设置排队等待流控规则

上图表示,如果访问资源testA的请求1秒超过1个请求,那么就会限流,然后把请求排队处理,每两秒处理一个。
这个可以通过postman或者Jmeter压测工具发送请求,观察输出日志时间间隔查看结果
设置关联流控规则

上图表示,如果调用资源testA的QPS超过1,那么就会限流资源testB的调用。
这个测试可以使用postman或者Jmeter压测工具不间断发送请求给testA然后再访问testB就能看见返回的限流提示信息
关联流控模式下的各种流控效果就是上家超标关联资源受限制
添加链路模式的流控规则

前面都是直接给资源【一个方法】设置流控规则,假如声明一个资源,然后有很多控制器方法调用资源,这时如果要分开对这些请求做流控,就能使用链路模式
首先要在service中声明一个SentinelResource 使用注解 @SentinelResource(value = "haha") 声明资源名,然后在controller中诸如并调用这个资源,然后配置文件中修改调用链路收敛为展开
service
@Service
public class SentinelTestService {
@SentinelResource(value = "abc")
public String testA(){
return "service TestA";
}
}
controller
@Autowired
SentinelTestService service;
@GetMapping("/getA")
public String getA(){
return service.testA();
}
@GetMapping("/getB")
public String getB(){
return service.testA();
}
配置文件
修改配置项 spring.cloud.sentinel.web-context-unify 为false关闭链路收敛
不修改即使配置了链路规则也不能限流
因为资源调用链路默认被收敛了没有展开就不能达到链路调用的流控效果
做完这些,重启项目,添加流控规则,然后访问getA请求就会发现会被限流,但是限流后返回的是异常,不好看。访问getB请求不会被限流
设置限流后的处理方法可以参照官网给的关于注解 @SentinelResource 的属性讲解:GitHub地址
这个注解要好好看
3、添加熔断降级规则
介绍
sentinel 具有服务熔断的功能,可以细化到每个资源上面
熔断的介绍:GitHub介绍
同样,可以在簇点链路或者降级规则中对指定资源设置降级规则
官方介绍里面都说了

Sentinel 提供以下几种熔断策略:
- 慢调用比例 (
SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。 - 异常比例 (
ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是[0.0, 1.0],代表 0% - 100%。 - 异常数 (
ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。
注意异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(BlockException)不生效。为了统计异常比例或异常数,需要通过 Tracer.trace(ex) 记录业务异常。
- RT(平均响应时间,秒级)
- 平均响应时间超出阈值且在时间窗口内通过的请求>=最小请求数,两个条件同时满足后触发降级
- 窗口期过后关闭断路器RT最大4900(更大的需要通过-Dcsp.sentinel.statistic.max.rt=XXXX才能生效)
- 异常比例(秒级)
- QPS >= 5 且异常比例(秒级统计)超过阈值时,触发降级;时间窗口结束后,关闭降级
- 异常数(分钟级)
- 异常数(分钟统计)超过阈值时,触发降级;时间窗口结束后,关闭降级
- 比例阈值
- 触发降级条件的请求在最小请求数中所占比例,0~100%
可以发现Sentinel的降级过程一样有三种状态:open、close、half open
添加规则
添加慢调用比例降级策略

上图表示资源 abc 被调用时,如果五个请求中只要有一个请求,在200百毫秒内调用资源abc时处理时长超过200毫秒就会被熔断降级然后返回提示信息,然后在5秒后进入half open 状态允许请求访问如果出错继续熔断。循环往复直至能成功处理。
测试时,可以给资源abc对应的方法中添加休眠代码,测试熔断效果
添加异常比例熔断策略

上图表示,如果五个请求中有一个请求调用资源haha时出现异常就会熔断降级返回提示信息。
添加异常数降级策略

上图表示在5个请求调用资源haha时如果出现了一个异常就会触发降级熔断条件,然后在5秒后变成halfopen状态,允许请求通过,查看是否能够处理请求
4、添加热点规则
介绍
热点规则全称是热点参数规则,即针对访问参数添加规则
何为热点
热点即经常访问的数据,很多时候我们希望统计或者限制某个热点数据中访问频次最高的TopN数据,并对其访问进行限流或者其它操作
Sentinel 利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。热点参数限流支持集群模式。
添加热点规则

上图表示,调用资源haha的请求的QPS数是1,如果请求的第一个参数值是String类型的abc,那么它的QPS就是998
页面要先添加热点规则后再次编辑
添加请求参数条件后要点击添加按钮
5、自定义流控处理方法
前面设置了规则后,如果超出规则要求就会返回sentinel的自带的提示语句或者直接是错误界面,当然也能设置自定义的提示信息
注解 @SentinelResource 可以设置这些,介绍地址:地址
设置自定义的流控处理方法时,方法中参数类型要和资源方法参数一致,需要有BlockException类型的参数 注解介绍官网都说了
代码
/**
* 使用注解 @SentinelResource 声明请求处理时超出处理限制的 fallbackMethod
* @param p1
* @param p2
* @return
*/
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey",blockHandler = "dealHandler_testHotKey")
public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
@RequestParam(value = "p2",required = false) String p2){
// int i = 10 / 0;
return "------testHotKey";
}
public CommonResult dealHandler_testHotKey(String p1, String p2, BlockException exception)
{
return new CommonResult(555,"参数值不是dd就只能一秒请求一次");
}
这时如果设置资源testHotKey的流控规则后,违反规则就会调用方法 dealHandler_testHotKey 作为流控规则处理方法
6、自定义规则处理方法优化
上面的自定义流控处理方法面临着代码冗余、跟逻辑代码混在一起、难看的问题,可以抽到一个类里面然后指定方法
注意参数一致和附带参数
public class MyHandler {
public static CommonResult handleException(BlockException exception){
return new CommonResult(123,"这是自定义的限流处理信息");
}
}
/**
* @SentinelResource 指定处理限流返回结果的处理方法
* 属性 value 就是在 sentinel 中添加热点规则的对象
* 属性 blockHandlerClass 值就是当前 requestHandle 处理请求限流时调用返回结果方法所在类
* 属性 blockHandler 值就是请求被限流时都要调用的方法名
* 此过程建议 CV
* @return 限流报文
*/
@GetMapping("/byResource")
@SentinelResource(value = "byResource",
blockHandlerClass = MyHandler.class,
blockHandler = "handleException")
public CommonResult byResource() {
return new CommonResult(200,"按资源名称限流测试OK",new Payment(2020L,"serial001"));
}
7、自定义fallbackMethod
上面说到自定义流控处理方法,那么也能够自定义降级fallbackMethod
一样使用注解 SentinelResource 完成
exceptionsToIgnore 声明忽略属性,就是说出现了哪些情况不触动上面配置的方法
@RestController
public class Consumer9011Controller {
@Autowired
FeignConsumerService feignConsumerService;
/**
* @SentinelResource value 声明限流对象名
* fallbackClass 声明熔断降级 fallbackMethod 所在类
* fallback 声明 fallbackMethod 名
* blockHandlerClass 声明限流处理方法所在类
* blockHandler 声明限流处理方法名
* exceptionsToIgnore 声明忽略属性,就是说出现了哪些情况不触动上面配置的方法
* @param id 查询 id
* @return 公共返回结果
*/
@GetMapping("/consumer/get/{id}")
@SentinelResource(
value = "getPaymentbangbang",
fallbackClass = MyHandler.class,
fallback = "myFallback",
blockHandlerClass = MyHandler.class,
blockHandler = "myBlockHandler",
exceptionsToIgnore = {IllegalArgumentException.class}
)
public CommonResult getPaymentById(@PathVariable("id") Long id) throws Exception {
if(id == 666){
throw new IllegalArgumentException("尊贵的666用户不受限制");
}
if (id == 123){
throw new Exception("我说他出错了");
}
return feignConsumerService.getPaymentById(id);
}
}
public class MyHandler {
public static CommonResult myFallback(@PathVariable("id") Long id, Throwable e){
return new CommonResult(444,"fallbackMethod"+e.getMessage());
}
public static CommonResult myBlockHandler(@PathVariable("id") Long id,BlockException e){
return new CommonResult(555,"限流响应");
}
}
注意参数类型和附带参数
启动工程设置降级规则,查看提示结果
8、和openFeign一起使用
这个需要两个服务提供者、一个服务调用模块完成后,再进行规则配置,中间使用openfeign完成功能调用
需要注意开启Sentinel对feign的支持
# If true, an OpenFeign client will be wrapped with a Sentinel circuit breaker
# 如果为true,OpenFeign客户端将使用Sentinel断路器进行包装
feign.sentinel.enabled=true
9、Sentinel 配置的持久化
可以发现,每次做完修改后重启项目,刷新sentinel会发现配置不见了,那么就需要持久化配置,需要配合nacos完成
先引入场景依赖
<!--SpringCloud ailibaba sentinel-datasource-nacos -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
在配置文件中添加配置
sentinel:
datasource:
ds1:
nacos:
server-addr: localhost:8848
dataId: ${spring.application.name}
groupId: DEFAULT_GROUP
data-type: json
rule-type: flow
在nacos中添加配置
[
{
"resource": "haha",
"limitApp": "default",
"grade": 1,
"count": 1,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
key 解释
- resource:资源名称;
- limitApp:来源应用;
- grade:阈值类型,0表示线程数,1表示QPS;
- count:单机阈值;
- strategy:流控模式,0表示直接,1表示关联,2表示链路;
- controlBehavior:流控效果,0表示快速失败,1表示Warm Up,2表示排队等待;
- clusterMode:是否集群。
测试
启动项目添加流控规则,关闭项目刷新sentinel,然后重启项目刷新sentinel,发现配置还在
扩展
使用nacos作为规则配置数据源:地址
示例代码:地址

浙公网安备 33010602011771号