Sentinel五大规则详解

Sentinel五大规则学习
本次演示以sentinel 1.8.0版本为例,讲解sentinel中流控、降级、热点、系统、授权五大规则。
一、流控规则
流量控制,其原理是监控应用流量的QPS(每秒查询率) 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。
资源名:接口路径名
针对来源:指定对哪个微服务进行限流,默认指default,意思是不区分来源,全部限制
阈值类型和单机阈值:
- QPS(每秒请求数量):: 当调用该接口的QPS达到阈值的时候,进行限流
- 线程数:当调用该接口的线程数达到阈值的时候,进行限流
是否集群:暂不需要集群
流控模式:
- 直接:直接流控模式是最简单的模式,当指定的接口达到限流条件时开启限流。
- 关联:当指定接口关联的接口达到限流条件时,对指定接口开启限流。
- 链路:A、B接口都在调用C接口,A、B接口谁调用C达到限流条件就限流谁。
流控效果:
- 快速失败(默认):直接失败,抛出异常,不做任何额外的处理,是最简单的效果。
- Warm Up:它从开始阈值到最大QPS阈值会有一个缓冲阶段,一开始的阈值是最大QPS阈值的 1/3,然后慢慢增长,直到最大阈值,适用于将突然增大的流量转换为缓步增长的场景。
- 排队等待:让请求以均匀的速度通过,单机阈值为每秒通过数量,其余的排队等待; 它还会让设置一个超时时间,当请求超过超时间时间还未处理,则会被丢弃。
主要演示三种流控模式,演示之前工作:
导入sentinel依赖:
<!-- SpringBoot 整合 nacos-sentinel 持久化 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<version>1.8.0</version>
</dependency>
配置文件:
server:
port: 8080
spring:
application:
name: mumber-producer #服务名程
cloud:
nacos:
discovery:
server-addr: localhost:8848 # nacos默认端口地址为8848
enabled: true
sentinel:
transport:
dashboard: localhost:8718 #sentinel-dashboard 地址
eager: true
web-context-unify: false #关闭context整合
开启sentinel控制台:
#jar命令启动,自定义端口号(控制台本身是一个SpringBoot项目)
java -Dserver.port=8718 -Dcsp.sentinel.dashboard.server=localhost:8718 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.0.jar
启动mumber-producer服务注册到控制台
1 直接模式
直接流控模式是最简单的模式,当指定的接口达到限流条件时开启限流。
- java代码
@RestController
@Slf4j
public class MumberController1 {
@RequestMapping("/message1")
@SentinelResource(value = "message1", blockHandler = "insertUserBlockHandler")
public String message1() {
return "message1" + "";
}
}
/**
* blockHandler为自定义的提示方法
* 必须为public、返回类型、参数类型与原方法一致,额外加一个BlockException参数
* @return
*/
public String insertUserBlockHandler(BlockException e){
return "当前访问人数太多,请稍后重试!";
}
- 添加直接规则
- 访问接口测试
http://localhost:8080/message1
当每秒请求次数超过1次时,会进行限流。
2 关联模式
当指定接口关联的接口达到限流条件时,对指定接口开启限流。(孩子惹事,家长负责)
- java代码
@RestController
@Slf4j
public class MumberController1 {
@RequestMapping("/message1")
@SentinelResource(value = "message1", blockHandler = "insertUserBlockHandler")
public String message1() {
return "message1接口..." + "";
}
@RequestMapping("/message2")
@SentinelResource(value = "message2", blockHandler = "insertUserBlockHandler")
public String message2() {
return "message2接口...";
}
/**
* blockHandler为自定义的提示方法
* 必须为public、返回类型、参数类型与原方法一致,额外加一个BlockException参数
* @return
*/
public String insertUserBlockHandler(BlockException e){
return "当前访问人数太多,请稍后重试!";
}
}
- 添加关联规则
- 访问测试
单独访问message1、message2都不会达到限流,只有频繁访问message2(超过每秒1次时),再去访问message1,则message1会限流。
3 链路模式
当A、B接口两个接口都在调用C接口,A、B接口谁调用C达到限流条件就限流谁,另一个接口不受影响。
- java代码
@Service
@Slf4j
public class MumberServiceImpl {
@SentinelResource(value = "message")
public void message() {
log.info("--->message");
}
}
@RestController
@Slf4j
public class MumberController1 {
@Autowired
private MumberServiceImpl mumberServiceImpl;
@RequestMapping("/message1")
@SentinelResource(value = "message1", blockHandler = "insertUserBlockHandler")
public String message1() {
String message = mumberServiceImpl.message();
return "message1接口..." + "调用了" + message;
}
@RequestMapping("/message2")
@SentinelResource(value = "message2", blockHandler = "insertUserBlockHandler")
public String message2() {
String message = mumberServiceImpl.message();
return "message2接口..." + "调用了" + message;
}
/**
* blockHandler为自定义的提示方法
* 必须为public、返回类型、参数类型与原方法一致,额外加一个BlockException参数
* @return
*/
public String insertUserBlockHandler(BlockException e){
return "当前访问人数太多,请稍后重试!";
}
}
- 添加配置
server:
port: 8080
spring:
application:
name: mumber-producer #服务名程
cloud:
nacos:
discovery:
server-addr: localhost:8848 # nacos默认端口地址为8848
enabled: true
sentinel:
transport:
dashboard: localhost:8718 #sentinel-dashboard 地址
eager: true
#添加这行配置
web-context-unify: false #关闭context整合
- 添加链路规则
理论上此时通过message2调用message接口不受影响,通过message1调用message接口则会限流。
但此处遇到一个bug,频繁访问message1接口时控制台报错:
百度许久依旧没有找到答案,后期如果解决了我会及时更新这篇笔记以及贴出解决方案。
二、降级规则
资源名:接口路径名
熔断策略:
-
慢调用比例(以前的版本也叫RT):选择一个慢调用比例作为阈值。
引入一个场景:A模块调用B模块
- 最大RT:Response Time 最大响应时间,即A调用B,B超过这个时间响应即为慢调用。
- 比例阈值:百分比,即访问接口慢调用达到百分之多少时,采用服务降级。
- 熔断时长:即触发熔断后,熔断持续的时长,如A调用B,B响应太慢,因此A模块采用降级处理,在一个时间段之内不会重复调用B。超过这个时间段过后再进行调用。
- 最小请求数:熔断触发的最小请求数(避免1次2次偶尔响应时间慢就开启降级处理,没必要)。
-
异常比例:
- 比例阈值:百分比,即访问接口异常达到百分之多少时,采用服务降级。
- 熔断时长:即触发熔断后,熔断持续的时长。
- 最小请求数:熔断触发的最小请求数。
-
异常数:
- 异常数:访问接口异常的次数达到多少触发熔断处理。
- 熔断时长:与上面一致。
- 最小请求数:与上面一致。
现对三种降级策略开启演示:
1 慢调用比例
- java代码
@Service
@Slf4j
public class MumberServiceImpl {
public String message(int id) {
if (id % 2 == 0){
try {
Thread.sleep(500); //当传递过来的参数为偶数时,休眠500毫秒实现慢调用
} catch (Exception e){
e.printStackTrace();
}
return "slow message";
}
return "fast message";
}
}
@RestController
@Slf4j
public class MumberController1 {
@Autowired
private MumberServiceImpl mumberServiceImpl;
/**
* 降级策略---慢调用比例
*/
@GetMapping("/getMessage")
@SentinelResource(value = "getMessage", blockHandler = "insertUserBlockHandler")
public String getMessage(@RequestParam("id") int id){
log.info("--->:{}" + id);
return mumberServiceImpl.Message(id);
}
/**
* blockHandler为自定义的提示方法
* 必须为public、返回类型、参数类型与原方法一致,额外加一个BlockException参数
* @return
*/
public static String insertUserBlockHandler(int id,BlockException e){
return "当前访问人数太多,请稍后重试!" ;
}
}
- 新增熔断降级
- 测试接口
localhost:8080/getMessage?id=2
携带偶数参数连续访问的接口占比50%时,会触发降级处理:
localhost:8080/getMessage?id=1
携带奇数参数时不受限制:
2 异常比例
- java代码
@Service
@Slf4j
public class MumberServiceImpl {
public String Message(int id) {
if (id % 2 == 0){
int i = 3 / 0; //人为构造一个异常
return "异常 message";
}
return "普通 message";
}
}
@RestController
@Slf4j
public class MumberController1 {
@Autowired
private MumberServiceImpl mumberServiceImpl;
/**
* 降级策略---异常比例
*/
@GetMapping("/getMessage")
@SentinelResource(value = "getMessage", blockHandler = "getMessageException")
public String getMessage(@RequestParam("id") int id){
log.info("--->:{}" + id);
return mumberServiceImpl.Message(id);
}
/**
* blockHandler为自定义的提示方法
* 必须为public、返回类型、参数类型与原方法一致,额外加一个BlockException参数
* @return
*/
public static String getMessageException(int id, BlockException e){
return "访问接口异常,请稍后重试!" ;
}
}
- 添加异常比例
- 测试
当携带参数为偶数时,会触发异常,当访问这个异常接口占比达到50%时会降级处理。
localhost:8080/getMessage?id=2
携带偶数参数连续访问的接口占比50%时,会触发降级处理:
localhost:8080/getMessage?id=1
携带奇数参数时不受限制:
3 异常数,与异常比例类似,此处不再演示,读者一看就会。
三、热点规则
在进行RESTful 设计的时候,一般都需要在 Action 的处理方法中进行请求参数的接收,于是这个时候可以针对于参数进行限流,这种规则就称为热点规则。
热点参数流控规则是一种更细粒度的流控规则, 它允许将规则具体到参数上。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WNnRXjKp-1670498950020)(D:\笔记\sentinel\热点规则.png)]
资源名:接口路径名
参数索引:一般接口都有参数,从接口的第一个参数开始,以0为下标累加,每个参数都有一个下标。每个接口独立计算。
单机阈值:接口每秒的访问数。
统计窗口时长:限流接口的时效。
是否集群:默认不集群。
参数例外项:参数例外项就是可以达到更加细粒度的控制,比如我们的某个被设置为限流的参数,可以通过参数例外项设置参数具体等于某个特殊的值的时候,触发不同的限流效果。例如有参数userId,普通设置为一个阈值,当userId等于某个具体的数时,设置特殊阈值。
代码演示:
- java代码
@RestController
@Slf4j
public class MumberController2 {
@RequestMapping("/user")
@SentinelResource(value = "user", blockHandler = "fail")
//此处age设置为Integer而非int,目的是Integer可以为null,而int不行
public String user(String name,Integer age) {
return "姓名:" +name + "---" + "年龄:" + age;
}
/**
* blockHandler为自定义的提示方法
* @return
*/
public String fail(String name,Integer age, BlockException e){
return "接口参数被限流了,请稍后重试!" ;
}
}
- 添加限流规则
- 访问测试
频繁访问限流的接口:localhost:8080/user?name=zhnagsan
频繁访问未被限流的接口:localhost:8080/user?age=20,无论怎么访问,都没有限流提示。
- 修改user接口第一个参数限流的参数例外项,当name为zhangsan时,限流阈值修改为3(每秒允许访问3次,超过则限流)
再次频繁访问限流的接口:localhost:8080/user?name=zhnagsan,发现限流速度比刚才慢了。
四、系统规则
系统保护规则是从应用级别的入口流量进行控制,从单台机器的总体 Load、RT、入口 QPS 、CPU使用率和线程数五个维度监控应用数据,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量 (进入应用的流量) 生效。
- Load(仅对 Linux/Unix-like 机器生效):当系统 load1 超过阈值,且系统当前的并发线程数超过 系统容量时才会触发系统保护。系统容量由系统的 maxQps * minRt 计算得出。设定参考值一般 是 CPU cores * 2.5。
- RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
- 线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
- 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。
- CPU使用率:当单台机器上所有入口流量的 CPU使用率达到阈值即触发系统保护
此处直接贴出alibaba sentinel官方的介绍,通俗易懂,就不演示实现了。
五、授权规则
授权规则可以对请求方来源做判断和控制。
- 白名单:来源(origin)在白名单内的调用者允许访问
- 黑名单:来源(origin)在黑名单内的调用者不允许访问
资源名:接口名
流控应用:是来源者的名单。
代码演示:
- java代码
首先新建一个RequestOriginParser的实现类,Sentinel是通过RequestOriginParser这个接口的parseOrigin来获取请求的来源的。
@Component
@Slf4j
public class RequestOriginParserDefinition implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest request) {
String serviceName = request.getParameter("serviceName"); //接收请求参数
if (serviceName == null || "".equals("serviceName")){ //如果参数内容为空
serviceName = request.getHeader("serviceName");
}
log.info("授权信息serviceName--->" + serviceName);
if (StringUtils.isEmpty(serviceName)){
return request.getRemoteAddr(); //根据ip地址处理
}
return serviceName;
}
}
@RequestMapping("/message1")
@SentinelResource(value = "message1", blockHandler = "insertUserBlockHandler")
public String message1() {
String message = mumberServiceImpl.message();
return "message1接口..." + "调用了" + message;
}
对于message1这个接口调用mumberServiceImpl的message()接口,在没有配置授权规则时,是能正常访问的。
- 配置授权规则
- 采用postMan工具测试,为该接口参数serviceName设置配置的值admin
- 此处只是采用postman进行了简单的测试,在实际开发中,比如A服务调用B服务的某个接口,是不可能采用postman手动携带参数的,需要在接口中携带参数信息。




更多推荐
所有评论(0)