https://github.com/alibaba/Sentinel
中文:https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
Sentinel 具有以下特征:
与Hystrix对比
Hystrix | Sentinel |
---|---|
需要程序员自己手工搭建监控平台 | 单独一个组件,可以独立出来 |
没有一套web界面可以给我们进行更加细粒度化的配置 | 直接界面的细粒度统一配置 |
https://github.com/alibaba/Sentinel/releases
官方使用文档:https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html#_spring_cloud_alibaba_sentinel
解决微服务中的各种问题
核心库
Java客户端,不依赖于任何框架/库,能够运行于所有Java运行时环境,同时对Dubbo/Spring Cloud等框架也有较好的支持
控制台
Danshboard,基于Spring Boot开发,打包后可以直接运行。不需要额外的Tomcat等应用容器
下载
官方下载地址:https://github.com/alibaba/Sentinel/releases
下载到本地:sentinel-dashboard-1.7.0.jar
运行命令
前提是Java8+环境OK与8080端口不能被占用
命令:java -jar sentinel-dashboard-1.7.0.jar
访问sentinel管理页面
地址:http://localhost:8080
登录账号密码均为:sentinel
http://localhost:8848/nacos
Module
新建cloudalibaba-sentinel-service8401工程
Pom
<dependencies>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cspgroupId>
<artifactId>sentinel-datasource-nacosartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
dependencies>
Yaml
server:
port: 8401
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
#配置 Sentinel dashboard 地址
dashboard: localhost:8080
#sentinel会启动一个http server与dashboard进行通信,占用该端口
port: 8719 #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口
主启动
@EnableDiscoveryClient
@SpringBootApplication
public class MainApp8401 {
public static void main(String[] args) {
SpringApplication.run(MainApp8401.class,args);
}
}
业务类FlowLimitController
@RestController
public class FlowLimitController {
@GetMapping("/testA")
public String testA() {
return "------testA";
}
@GetMapping("/testB")
public String testB() {
return "------testB";
}
}
启动Sentinel8080 —> java -jar sentinel-dashboard-1.7.0.jar
启动微服务8401
启动微服务8401后查看sentinel控制台,发现空空如也,啥都没有
这是因为sentinel采用了懒加载机制,只要让它检测到就会有对应监控服务
http://localhost:8401/testA + http://localhost:8401/testB
出现了上述结果就说明sentinel8080正在监控微服务8401!
上图概念解释说明
资源名:唯一名称,默认请求路径
针对来源:Sentinel可以针对调用者进行限流,填写微服务名,默认default (不区分来源)
阈值类型/单机阈值:
是否集群:不需要集群
流控模式:
流控效果
直接 —> 快速失败
配置及说明
注:若阈值类型为线程数的话,表示只允许一个线程处理该请求(干活的只允许有一个)
测试
快速点击访问http://localhost:8401/testA(超过一秒一次)
结果:Blocked by Sentinel (flow limiting)
关联是当关联的资源达到阈值后,就限流自己,当与A相关联的B达到阈值后,就限流A,即B惹事,A挂了
配置及说明
当关联资源的/testB的QPS阈值超过1时,就限流/testA的Rest访问地址
测试
用Postman模拟并发密集访问testB
运行后发现访问testA挂了,—> 访问http://localhost:8401/testA 结果:Blocked by Sentinel (flow limiting)
链路流控模式指的是,当从某个接口过来的资源达到限流条件时,开启限流;它的功能有点类似于针对来源配置项,区别在于:针对来源是针对上级微服务,而链路流控是针对上级接口,也就是说它的粒度更细
这是默认的流控处理,直接失败,抛出异常 Blocked by Sentinel (flow limiting)
规则源码:com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController
官网
公式:阈值除以coldFactor(默认为3),经过预热时长后会达到阈值
即请求QPS从阈值/3开始,经过预热时长逐渐升至指定的QPS阈值
表明一开始的单机阈值为10/3为3,然后预热时长为3,表明经过3秒时长后会逐渐升至指定的QPS阈值
规则源码:com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController
场景
秒杀系统在开启的瞬间,会有很多流量上来,很有可能把系统打死,预热方式就是把为了保护系统,可慢慢的把流量放迸慢慢的把阀值增长到设置的阀值
官网
配置及说明
/testA每秒处理一次请求,超过的话就排队等待,等待的超时时间为20000毫秒
配置源码:com.alibaba.csp.sentinel.slots.block.flow.controller.RateLimiterController
测试
开启Postman测试,每隔0.1秒发送一个请求
发现只有第一次立即响应了,其他几次都是接近一秒后进行响应,测试成功!
除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。一个服务常常会调用别的模块,可能是另外的一个远程服务、数据库,或者第三方 API 等。例如,支付的时候,可能需要远程调用银联提供的 API;查询某个商品的价格,可能需要进行数据库查询。然而,这个被依赖服务的稳定性是不能保证的。如果依赖的服务出现了不稳定的情况,请求的响应时间变长,那么调用服务的方法的响应时间也会变长,线程会产生堆积,最终可能耗尽业务自身的线程池,服务本身也变得不可用
现代微服务架构都是分布式的,由非常多的服务组成。不同服务之间相互调用,组成复杂的调用链路。以上的问题在链路调用中会产生放大的效果。复杂链路上的某一环不稳定,就可能会层层级联,最终导致整个链路都不可用。因此我们需要对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩。熔断降级作为保护自身的手段,通常在客户端(调用端)进行配置。
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 1.8.0 及以上版本
源码规则类:com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule
熔断降级规则(DegradeRule)包含下面几个重要的属性:
Field | 说明 | 默认值 |
---|---|---|
resource | 资源名,即规则的作用对象 | |
grade | 熔断策略,支持慢调用比例/异常比例/异常数策略 | 慢调用比例 |
count | 慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值 | |
timeWindow | 熔断时长,单位为 s | |
minRequestAmount | 熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断(1.7.0 引入) | 5 |
statIntervalMs | 统计时长(单位为 ms),如 60*1000 代表分钟级(1.8.0 引入) | 1000 ms |
slowRatioThreshold | 慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入) |
何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制
https://github.com/alibaba/Sentinel/wiki/热点参数限流
com.alibaba.csp.sentinel.slots.block.BlockException
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey",blockHandler = "dealTestHotKey") //value随便写,只要不重复
public String testHotKey(String p1,String p2) {
return "testHotKey";
}
//兜底方法
public String dealTestHotKey(String p1, String p2, BlockException exception) {
return "deal test hot key ! ";
}
sentinel控制台新增热点规则
这样方法testHotKey中的第一个参数只要QPS超过每秒一次,马上降级处理,若@SentinelResource注解没配置blockHandler属性的话,异常就会打到前台被用户看到,若配置了则使用自定义的兜底方法
http://localhost:8401/testHotKey?p1=a -> QPS超过阈值则失败!
http://localhost:8401/testHotKey?p1=a&p2=b -> QPS超过阈值则失败!
http://localhost:8401/testHotKey?p2=b -> 成功!
上述案例演示了第一个参数p1当QPS超过一以后马上被限流
我们期望p1参数当它是一个特殊的值的时候,它的限流值和平时不一样
比如当p1的值等于5时,它的阈值可以达到200
注意:参数的类型必须为8中基本数据类型或String
http://localhost:8401/testHotKey?p1=5 -> 成功!
http://localhost:8401/testHotKey?p1=3 -> 失败,QPS>1会被限流
当p1=5的时候,阈值会变为200,当p1不等于5的时候。阈值就是平常的1
Sentinel 系统自适应限流从整体维度对应用入口流量进行控制,结合应用的 Load、CPU 使用率、总体平均 RT、入口 QPS 和并发线程数等几个维度的监控指标,通过自适应的流控策略,让统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性
系统保护规则是从应用级别的入口流量进行控制,从单台机器的 load、CPU 使用率、平均 RT、入口 QPS 和并发线程数等几个维度监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性
系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(EntryType.IN
),比如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量
系统规则支持以下的模式:
maxQps * minRt
估算得出。设定参考值一般是 CPU cores * 2.5
注:CommonResult为自己封装的返回信息的泛型类,返回状态码,信息及相应数据
@RestController
public class RateLimitController {
@GetMapping("/byResource")
@SentinelResource(value = "byResource",blockHandler = "handleException")
public CommonResult byResource() {
return new CommonResult(200,"按资源名称限流测试OK",new Payment(2020L,"serial001"));
}
public CommonResult handleException(BlockException exception) {
return new CommonResult(444,exception.getClass().getCanonicalName()+"\t 服务不可用");
}
}
结合我们的代码注解,表明一秒钟内查询次数大于1就跑到我们自定义的处理限流的方法,
一秒钟点击一下,ok!
超过上述问题,疯狂点击,返回了自定义的限流处理信息
{"code":444,"message":"com.alibaba.csp.sentinel.slots.block.flow.FlowException\t 服务不可用","data":null}
参考之前的流控规则的基本介绍
系统默认的,没有体现我们自己的业务要求。
依照现有条件,我们自定义的处理方法又和业务代码耦合在一块,不直观
每个业务方法都添加一个兜底的,那代码膨胀加剧
全局统—的处理方法没有体现
public class CustomerBlockHandler {
public static CommonResult handlerException(BlockException exception) {
return new CommonResult(4444,"按客戶自定义 global handler exception1",new Payment(2020L,"serial003"));
}
public static CommonResult handlerException2(BlockException exception) {
return new CommonResult(4444,"按客戶自定义 global handler exception2",new Payment(2020L,"serial003"));
}
}
@GetMapping("/rateLimit/customerBlockHandler")
@SentinelResource(value = "customerBlockHandler",
blockHandlerClass = CustomerBlockHandler.class,
blockHandler = "handlerException2")
public CommonResult customerBlockHandler() {
return new CommonResult(200,"按客戶自定义",new Payment(2020L,"serial003"));
}
一秒钟点击一下,ok!
超过上述问题,疯狂点击,返回了自定义的限流处理信息
{"code":4444,"message":"按客戶自定义 global handler exception2","data":{"id":2020,"serial":"serial003"}}
可以看到是CustomerBlockHandler的handlerException2方法执行了,配置成功!
value
资源名称,必需项,因为需要通过resource name找到对应的规则,这个是必须配置的。
entryType
entry 类型,可选项,
有IN和OUT两个选项,默认为 EntryType.OUT。
public enum EntryType {
IN("IN"),
OUT("OUT");
}
blockHandler
blockHandler 对应处理 BlockException 的函数名称,可选项。
blockHandler 函数访问范围需要是 public,返回类型需要与原方法相匹配,
参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException。
blockHandlerClass
blockHandler 函数默认需要和原方法在同一个类中,如果希望使用其他类的函数,
则需要指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static
函数,否则无法解析。
fallback
fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。
fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。
fallbackClass
fallbackClass的应用和blockHandlerClass类似,fallback 函数默认需要和原方法在同一个类中。
若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
defaultFallback(since 1.6.0)
如果没有配置defaultFallback方法,默认都会走到这里来。
默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑。
默认 fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。
若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。
exceptionsToIgnore(since 1.6.0)
用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。
sentinel整合 ribbon + openfeign + fallback
新建cloudalibaba-provider-payment9003/9004
POM
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
com
cloud-api-commons
1.0-SNAPSHOT
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-actuator
YAML
server:
port: 9003
spring:
application:
name: nacos-payment-provider
cloud:
nacos:
discovery:
server-addr: localhost:8848 #配置Nacos地址
主启动
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain9003 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain9003.class, args);
}
}
业务类
@RestController
public class PaymentController {
@Value("${server.port}")
private String serverPort;
public static HashMap<Long, Payment> hashMap = new HashMap<Long, Payment>();
static {
hashMap.put(1L,new Payment(1L,"28a8c1e3bc2742d8848569891fb42181"));
hashMap.put(2L,new Payment(2L,"bba8c1e3bc2742d8848569891ac32182"));
hashMap.put(3L,new Payment(3L,"6ua8c1e3bc2742d8848569891xt92183"));
}
@GetMapping(value = "/paymentSQL/{id}")
public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id) {
Payment payment = hashMap.get(id);
return new CommonResult<Payment>(200,"from mysql,serverPort: " + serverPort, payment);
}
}
测试地址
http://localhost:9003/paymentSQL/1
新建cloudalibaba-consumer-nacos-order84
POM
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
dependency>
<dependency>
<groupId>comgroupId>
<artifactId>cloud-api-commonsartifactId>
<version>1.0-SNAPSHOTversion>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
dependencies>
YAML
server:
port: 84
spring:
application:
name: nacos-order-consumer
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080
port: 8719
主启动
@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients
public class OrderNacosMain84 {
public static void main(String[] args) {
SpringApplication.run(OrderNacosMain84.class, args);
}
}
业务类
ApplicationContextConfig:用来给容器中填一个带负载均衡的RestTemplate组件
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
CircleBreakerController
@RestController
public class CircleBreakerController {
public static final String SERVICE_URL = "http://nacos-payment-provider";
@Resource
private RestTemplate restTemplate;
@RequestMapping("/consumer/fallback/{id}")
//@SentinelResource(value = "fallback") //没有配置
//@SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback只负责业务异常
//@SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler只负责sentinel控制台配置违规
@SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler",
exceptionsToIgnore = {IllegalArgumentException.class})
public CommonResult<Payment> fallback(@PathVariable Long id) {
CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/"+id, CommonResult.class,id);
if (id == 4)
throw new IllegalArgumentException ("IllegalArgumentException,非法参数异常....");
else if (result.getData() == null)
throw new NullPointerException ("NullPointerException,该ID没有对应记录,空指针异常");
return result;
}
//fallback
public CommonResult<Payment> handlerFallback(@PathVariable Long id,Throwable e) {
Payment payment = new Payment(id,"null");
return new CommonResult<Payment>(444,"兜底异常handlerFallback,exception内容 "+e.getMessage(),payment);
}
//blockHandler
public CommonResult<Payment> blockHandler(@PathVariable Long id, BlockException blockException) {
Payment payment = new Payment(id,"null");
return new CommonResult<Payment>(445,"blockHandler-sentinel限流,无此流水: blockException "+blockException.getMessage(), payment);
}
}
@SentinelResource(value = “fallback”)
http://localhost:84/consumer/fallback/1 -> 返回正常
http://localhost:84/consumer/fallback/4 -> 报错!非法参数异常
http://localhost:84/consumer/fallback/8 -> 报错!空指针异常
@SentinelResource(value = “fallback”,fallback = “handlerFallback”)
http://localhost:84/consumer/fallback/1 -> 返回正常
http://localhost:84/consumer/fallback/4 -> 返回指定内容
{"code":444,"message":"兜底异常handlerFallback,exception内容 IllegalArgumentException,非法参数异常....","data":{"id":4,"serial":"null"}}
http://localhost:84/consumer/fallback/8 -> 返回指定内容
{"code":444,"message":"兜底异常handlerFallback,exception内容 NullPointerException,该ID没有对应记录,空指针异常","data":{"id":5,"serial":"null"}}
@SentinelResource(value = “fallback”,blockHandler = “blockHandler”)
sentinel控制台配置对应流控规则
http://localhost:84/consumer/fallback/1 -> 返回正常
http://localhost:84/consumer/fallback/4 -> QPS<1报错,大于1时候返回指定内容
{"code":445,"message":"blockHandler-sentinel限流,无此流水: blockException null","data":{"id":4,"serial":"null"}}
http://localhost:84/consumer/fallback/8 -> QPS<1报错,大于1时候返回指定内容
{"code":445,"message":"blockHandler-sentinel限流,无此流水: blockException null","data":{"id":8,"serial":"null"}}
@SentinelResource(value = “fallback”,fallback = “handlerFallback”,blockHandler = “blockHandler”)
sentinel控制台配置对应流控规则
当QPS<1时:
http://localhost:84/consumer/fallback/1 -> 返回正常
http://localhost:84/consumer/fallback/4 -> 返回指定内容
{"code":444,"message":"兜底异常handlerFallback,exception内容 IllegalArgumentException,非法参数异常....","data":{"id":4,"serial":"null"}}
http://localhost:84/consumer/fallback/8 -> 返回指定内容
{"code":444,"message":"兜底异常handlerFallback,exception内容 NullPointerException,该ID没有对应记录,空指针异常","data":{"id":8,"serial":"null"}}
当QPS>1时:
http://localhost:84/consumer/fallback/1 -> 返回指定内容
{"code":445,"message":"blockHandler-sentinel限流,无此流水: blockException null","data":{"id":1,"serial":"null"}}
http://localhost:84/consumer/fallback/4 -> 返回指定内容
{"code":445,"message":"blockHandler-sentinel限流,无此流水: blockException null","data":{"id":4,"serial":"null"}}
http://localhost:84/consumer/fallback/8 -> 返回指定内容
{"code":445,"message":"blockHandler-sentinel限流,无此流水: blockException null","data":{"id":8,"serial":"null"}}
若blockHandler和fallback都进行了配置,则被限流降级而抛出BlockException时只会进入blockHandler处理逻辑
POM
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
YAML
#对Feign的支持
feign:
sentinel:
enabled: true
业务类
带@FeignClient注解的业务接口
@FeignClient(value = "nacos-payment-provider",fallback = PaymentFallbackService.class)
public interface PaymentService {
@GetMapping("/paymentSQL/{id}")
CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
}
实现类PaymentFallbackService
@Component
public class PaymentFallbackService implements PaymentService {
@Override
public CommonResult<Payment> paymentSQL(Long id) {
return new CommonResult<>(44444, "服务降级返回,---PaymentFallbackService", new Payment(id,"errorSerial"));
}
}
controller
// OpenFeign
@Resource
private PaymentService paymentService;
@GetMapping(value = "/consumer/paymentSQL/{id}")
public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id) {
return paymentService.paymentSQL(id);
}
主启动类
添加@EnableFeignClients启动Feign的功能
http://localhost:84/paymentSQL/1
成功返回数据
{"code":200,"message":"from mysql,serverPort: 9003","data":{"id":1,"serial":"28a8c1e3bc2742d8848569891fb42181"}}
关闭服务提供者,看是否会进行超时服务降级
http://localhost:84/paymentSQL/1
{"code":44444,"message":"服务降级返回,---PaymentFallbackService","data":{"id":1,"serial":"errorSerial"}}
测试成功!
一旦我们重启应用,Sentinel规则将消失,生产环境需要将配置规则进行持久化
将限流配置规则持久化进Nacos保存,只要刷新8401某个rest地址,sentinel控制台的流控规则就能看到,只要Nacos里面的配置不删除,针对8401上Sentinel上的流控规则持续有效
修改cloudalibaba-sentinel-service8401
POM
添加做配置持久化所需要的依赖
<dependency>
<groupId>com.alibaba.cspgroupId>
<artifactId>sentinel-datasource-nacosartifactId>
dependency>
YAML
添加Nacos数据源配置 格式如下
spring:
cloud:
sentinel:
datasource:
ds1:
nacos:
server-addr: localhost:8848
dataid: ${spring.application.name}
groupid: DEFAULT_GROUP
data-type: json
rule-type: flow
修改后yaml
server:
port: 8401
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
#配置 Sentinel dashboard 地址
dashboard: localhost:8080
port: 8719 #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口
datasource:
ds1:
nacos:
server-addr: localhost:8848
dataId: cloudalibaba-sentinel-service
groupId: DEFAULT_GROUP
data-type: json
rule-type: flow
内容解释
resource:资源名称
limitApp:来源应用
grade:阈值类型,0表示线程数,1表示QPS
count:单机阈值
strategy:流控模式,0表示直接,1表示关联,2表示链路
controlBehavior:流控效果,0表示快速失败,1表示Warm Up,2表示排队等待
clusterMode:是否集群
重启后测试http://localhost:8401//rateLimit/byUrl
发现当QPS大于1时候流控规则起效果了,并且Sentinel控制台也显示出来了,说明持久化配置成功!