创建工程测试工程
1.导入依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.12.RELEASE</version>
</parent>
<dependencyManagement>
<dependencies>
<!-- spring cloud 总体依赖版本管理 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR12</version>
<scope>import</scope>
<type>pom</type>
</dependency>
<!-- spring cloud alibaba 总体依赖版本管理 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.7.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
</dependencies>
2.yml配置
server:
port: 9000
spring:
application:
name: nacos-sentinel
cloud:
nacos:
discovery:
server-addr: 192.168.8.128:8848
sentinel: # 配置sentinel信息
transport:
dashboard: 192.168.8.128:8858 # 配置sentinel服务器地址,客户端连接sentinel
port: 8719 # 代表sentinel客户端和控制台通信的端口,默认为8719,sentinel监控客户端
4.创建控制器
@RestController
public class SentinelController {
@RequestMapping("/fs")
public String show(){
return "hello world!";
}
}
访问: http://localhost:9000/fs
流控
1.资源名: 标识资源的唯一名称,默认为请求路径,也可以在客户端中使用@SentinelResource配置。
2.针对来源: Sentinel可以针对服务调用者进行限流,填写微服务名称即spring.application.name,默认为default,不区分来源。
3.阈值类型:
QPS(每秒钟的请求数量): 当调用该api的QPS达到阈值的时候,进行限流。
线程数: 当调用该api的线程数达到阈值的时候,进行限流。
4.单机阈值: 定义QPS或线程数的具体控制阈值。
5.是否集群: 默认不集群。
6.流控模式:
直接: 当api调用达到限流条件的时,直接限流。
关联: 当关联的资源请求达到阈值的时候,限流自己,例: 设置/aa和/bb,在/bb的关联中填入/aa,/aa在1s被访问5次(假设限制)则限流/bb
链路: 只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,则进行限流),例: 从指定/aa下访问/fs的请求才统计限流
7 流控效果:
快速失败: 直接失败。
Warm Up(预热): 设置预热时长,在预热时长内,处理请求上线为 请求数/预热时长,预热时长过后,恢复原单机阈值
排队等待: 匀速排队,让请求匀速通过,阈值类型必须设置为QPS,否则无效。
熔断
下图表示访问/fs控制单元的5次请求内,有50%的请求的响应时长超过100ms,则熔断3秒,熔断期间直接降级
熔断策略:
1 慢调用比例: 按照响应时间进行判断,比例,数量进行判断。
2.异常比例: 按照异常比例进行判断。
3 异常数量: 按照异常的数量进行判断。
最大RT: 响应时间,单位毫秒。指请求及响应的时间。最大RT :300,表示如果请求及响应时间超过300毫秒则为慢调用。
比例阈值: 取值[0.0-1.0],0表示0%,1.0表示100%。表示慢调用出现的比例。
熔断时长: 当满足熔断条件后,熔断时间。
最小请求数: 进行判断的最小请求的数量。
热点
简单说: 就是更具请求携带的不同的参数值,来采取不同的限制.
添加控制层代码: 在方法前加@SentinelResource(value = “firstResource(随意指定)”)
注意 热点 只能在 @SentinelResource该注解指定的名称中添加,不能直接添加到对应的控制单元上
@RestController
public class DemoController {
@RequestMapping("/fs")
@SentinelResource(value = "firstResource")
public String show(String name){
System.out.println(name);
return "hello world!";
}
}
下图就是在请求参数不为aa时,一秒内超过2个请求就降级,请求参数为aa时,一秒内超过5个请求就降级才降级
参数索引: 请求传入的参数索引,从0开始计数。即控制器方法参数表中的热点参数索引。
单机阈值: 与流控规则中的单机阈值含义相同。
统计窗口时长: 对单机阈值的流控限制统计窗口时长。如:单机阈值 3, 统计窗口时长 1 ,则1秒内QPS阈值为3。
设置热点参数: 当创建热点规则后,会在Sentinel Dashboard中热点规则中出现我们建立的规则。
在热点规则中点击编辑
参数类型: 热点参数数据类型。
参数值: 热点参数具体值。
限流阈: 当请求参数值与热点参数值相同时的QPS阈值。
添加按钮: 当设置好热点参数例外项后,一定要点击添加按钮,否则热点参数不生效
授权规则
就是让那些ip和访问,哪些ip不能访问
使用授权规则,必须在被Sentinel管理的应用这增加解析类型,根据IP实现授权规则限制
/**
* 自定义解析器。用于配合Sentinel实现授权管理的。
* 要求当前类型的对象,必须被spring容器管理。
*
* RequestOriginParser - 用于解析每个请求的解析器。
* 可以获取客户端IP地址。
*/
@Component
public class MyParser implements RequestOriginParser {
/**
* 接口中定义的唯一解析方法。用于解析请求对象的。
* @param httpServletRequest
* @return 解析后的结果。一般是客户端IP地址。
*/
@Override
public String parseOrigin(HttpServletRequest httpServletRequest) {
System.out.println("remoteAddr = " + remoteAddr);
System.out.println("remoteHost = " + httpServletRequest.getRemoteHost());
System.out.println("remotePort = " + httpServletRequest.getRemotePort());
return httpServletRequest.getRemoteAddr();
}
}
表示只有127.0.0.1才能访问该地址
1.流控应用: 具体访问这个资源的客户端,即客户端IP地址。多个地址使用逗号 ‘,’ 分隔。
2 授权类型: 即流控应用是否可访问当前被授权规则管理的资源。
- 白名单:可以访问。
- 黑名单:不可访问。
系统规则
系统规则是对整个系统进行设置的规则。阈值类型包含以下五种:
1.Load: 自适应(仅对 Linux/Unix-like 机器生效),系统的 load 作为启发指标,进行自适应系统保护。当系统 load超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的 maxQps minRt 估算得出。设定参考值一般是 CPU cores 2.5。
2.CPU使用率: 当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。
3.RT平均 RT,当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
4.线程数: 并发线程数,当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
5.QPS: 入口 QPS,当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。
@SentinelResource
利用这个注解可以自定义降级和发生异常时调用的方法
1.fallback回退: 在标注了@SentinelResouce注解的方法,发生了Java异常时的回退处理。
2.block回退: @SentinelResource资源访问不符合Sentinel控制台定义的规则时的回退。当没有定义Block回退时默认为Blocked by Sentinel (flow limiting)
* fallback - 是当前服务逻辑,发生异常的时候,Sentinel辅助回调的降级方法名称。
* 当方法抛出异常。触发fallback配置的方法,返回给客户端降级数据。
* 没有默认值。
* 方法定义要求:
* 1. fallback方法签名和当前方法签名,除方法名称外其他都一致。
* blockHandler - 是当前服务逻辑,触发Sentinel限制阈值时,Sentinel辅助回调的降级方法名。
* 当某限制规则被触发,blockHandler配置的方法运行,返回给客户端降级数据。
* 没有默认值。
* 方法定义要求:
* 1. blockHandler方法签名和当前方法签名,除方法名称和参数表外,都一致。
* 2. 参数表要求:包含当前方法所有参数,在参数表最后,增加BlockException参数。
* BlockException是Sentinel定义的规则异常顶级父类。有若干子类型。
* 异常参数对象的具体类型,代表触发了Sentinel约束的哪一种规则。
* FlowException - 流控规则
* ParamFlowException - 热点规则
* DegradeException - 降级规则
* AuthorityException - 授权规则
* SystemBlockException - 系统规则
@RestController
public class DemoController {
@GetMapping("/sayHello")
@SentinelResource(value = "firstResource", fallback = "sayHelloFallback", blockHandler = "sayHelloBlockHandler")
public String sayHello(String name){
System.out.println("sentinel name = " + name);
// 用于测试异常处理
if(name.equals("exception")){
throw new RuntimeException("测试异常处理");
}
return "您好:" + name;
}
public String sayHelloFallback(String name){
System.out.println("sayHelloFallback方法运行,参数是:" + name);
return "服务器忙,请稍后重试!";
}
public String sayHelloBlockHandler(String name, BlockException ex){
if(ex.getClass() == FlowException.class){
System.out.println("流控规则");
return "参与活动人数太多,请稍后重试!";
}
if(ex.getClass() == ParamFlowException.class){
System.out.println("热点规则");
return "查询的数据不存在!";
}
if(ex.getClass() == DegradeException.class){
System.out.println("降级规则");
return "服务器爆炸!";
}
if(ex.getClass() == AuthorityException.class){
System.out.println("授权规则");
return "您的权限不足,请联系管理员!";
}
if(ex.getClass() == SystemBlockException.class){
System.out.println("系统规则");
return "您访问的网站已下线,明天再来吧!";
}
System.out.println("其他问题");
return "未知原因";
}
}
配置持久化
Sentinel中各种流量控制可以借助持久化工具进行存储。示例中利用:Nacos配置中心存储相关配置。
1.在nocos中新增配置
2.配置内容:
[
{
"resource": "/demo01",
"limitApp": "default",
"grade": 1,
"count": 3,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
配置详解:
- resource:资源名,即限流规则的作用对象
- limitApp:流控针对的调用来源,若为 default 则不区分调用来源
- grade:限流阈值类型(QPS 或并发线程数);0代表根据并发线程数量来限流,1代表根据QPS来进行流量控制
- count:限流阈值
- strategy:流控模式,调用关系限流策略(0-直连,1-关联,2-链路)
- controlBehavior:流量控制效果(0-快速失败、1-Warm Up、2-排队等待)
- clusterMode:是否为集群模式
3.导入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
4.yml配置
server:
port: 8080
spring:
application:
name: nacos-sentinel
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
sentinel: # 配置sentinel信息
transport:
dashboard: 127.0.0.1:8858 # 配置sentinel服务器地址。
port: 8719 # 代表sentinel客户端和控制台通信的端口,默认为8719
datasource: # 配置sentinel规则存储的数据源
ds: # 定义数据源的key
nacos: # 指定nacos作为数据源
server-addr: 127.0.0.1:8848 # nacos服务器地址
data-id: hello # nacos中配置文件名称
group-id: world # nacos中配置文件所属分组, 默认DEFAULT_GROUP
data-type: json # nacos中配置文件类型, 默认json
rule-type: flow # nacos中配置文件定义的规则类型。
5.重启后,访问 http://localhost:9000/fs?name=test在不做任何规则配置的前提下,查看Sentinel控制台中的流控规则面板,查看是否存在流控规则信息。
存在!
执行流程
1.微服务启动
2.根据配置文件application.yml中的配置,动态访问Sentinel Datasource,读取持久化规则配置3.sentinel客户端占用端口8719,连接sentinel服务器(端口是8858)
4.如果有持久化的规则配置,在连接sentinel服务器的同时,提交持久化规则配置内容5.客户端浏览器请求微服务
6.微服务中的sentinel客户端拦截请求,上报请求信息到sentinel服务器(端口8858)
7.sentinel服务器检测已配置的规则限制(如:流控、降级、热点等)
8.sentinel服务器返回规则限制是否被触发(返回到sentinel客户端,端口是8719)
9.如果流控规则已触发,sentinel客户端直接返回降级(Blocked by sentinel),或调用SentinelResource注解配置的blockHandler返回托底数据。
10.如果流控规则未触发,微服务正常执行,并返回运行结果给客户端。|