随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、流量路由、熔断降级、系统自适应过载保护、热点流量防护等多个维度保护服务的稳定性。功能大致等价于Hystrix
Hystrix的缺点:
1)需要手工搭建监控平台
2)没有一套web界面进行细粒度的配置流量控制、速率控制、服务熔断、服务降级…
Sentinel 解决的问题:服务雪崩、服务降级、服务中断、服务限流
Sentinel 分为两个部分:
Sentinel 的开源生态:
学习资料
官网:https://github.com/alibaba/Sentinel
中文官网:https://github.com/alibaba/Sentinel/wiki
Sentinel 社区官方网站:https://sentinelguard.io/
spring_cloud_alibaba_sentinel:https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html#_spring_cloud_alibaba_sentinel
安装Sentinel控制台
下载地址:https://github.com/alibaba/Sentinel/releases
java -jar sentinel-dashboard-1.7.0.jar
NOTE:登录账号、密码:sentinel
需求:通过sentinel监控微服务8401
【第一步】启动Nacos8848
nacos安装目录下的bin目录,双击startup.cmd
【第二步】创建微服务8401
cloudalibaba-sentinel-service8401
1)修改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.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>runtimescope>
<optional>trueoptional>
dependency>
<dependency>
<groupId>cn.hutoolgroupId>
<artifactId>hutool-allartifactId>
<version>4.6.3version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
2)创建application.yml
配置文件,
server:
port: 8401
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
management:
endpoints:
web:
exposure:
include: '*'
3)创建启动类,
@EnableDiscoveryClient
@SpringBootApplication
public class MainApp8401
{
public static void main(String[] args) {
SpringApplication.run(MainApp8401.class, args);
}
}
4)创建业务类,controller
@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
【第五步】查看sentinel控制台 http://localhost:8080/
现象:控制台什么都没有
解释:Sentinel采用的懒加载机制,执行一次访问即可
测试地址1:http://localhost:8401/testA
测试地址2:http://localhost:8401/testB
字段说明
1)资源名:唯一名称,默认请求路径
2)针对来源:Sentinel 可以针对调用者进行限流,填写微服务名,默认 default (不区分来源)
3)阈值类型 / 单机阈值
QPS:(每秒钟的请求数量):调用该 API 的 QPS 达到阈值的时候, 进行限流
线程数:当调用该 API 的线程数达到阈值的时候,进行限流
4)是否集群:不需要集群
5)流控模式
直接
关联
链路
6)流控效果
快速失败
Warm Up
排队等待
请求达到限流条件时,直接限流→快速失败 系统默认
快速点击访问,http://localhost:8401/testA
结果:Blocked by Sentinel (flow limiting)
思考:默认fallback直接调用默认报错信息,自定义 fallback兜底方法
当关联的资源达到阈值,就限流自己
解释:当与A关联的资源B达到阀值后,就限流A自己
测试:/testA请求关联/testB请求,/testB请求达到阈值时,限流/testA请求
说明: JMeter做压力测试,3秒100个请求循环100次
请求:http://localhost:8401/testA
测试效果:Blocked by Sentinel (flow limiting)
只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)【API 级别的针对来源】
场景:多个请求调用了同一个微服务
直接失败,抛异常 Blocked by Sentinel (flow limiting)
源码:com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController
NOTE:直接->快速失败(默认的流控处理)
预热/冷启动方式,根据 codeFactory(冷加载因子,默认 3),从阈值 /CodeFactor,经过预热时长,才达到设置的 QPS 阈值 。
NOTE:Warm Up(
RuleConstant.CONTROL_BEHAVIOR_WARM_UP
)方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。
官网:https://github.com/alibaba/Sentinel/wiki/%E9%99%90%E6%B5%81—%E5%86%B7%E5%90%AF%E5%8A%A8
案例,阀值为10,预热时长设置5秒。
系统初始化的阀值为10 / 3 约等于3,即阀值刚开始为3;然后过了5秒后阀值才慢慢升高恢复到10
多次点击http://localhost:8401/testA,查看效果
应用场景:如:秒杀系统在开启的瞬间,会有很多流量上来,很有可能把系统打死,预热方式就是把为了保护系统,可慢慢的把流量放进来,慢慢的把阀值增长到设置的阀值。
匀速排队,让请求以匀速的速度通过,阈值类型必须设置 QPS,否则无效
设置含义:/testA每秒1次请求,超过的话就排队等待,等待的超时时间为20000毫秒。
源码:com.alibaba.csp.sentinel.slots.block.flow.controller.RateLimiterController
现代微服务架构都是分布式的,由非常多的服务组成。不同服务之间相互调用,组成复杂的调用链路。以上的问题在链路调用中会产生放大的效果。复杂链路上的某一环不稳定,就可能会层层级联,最终导致整个链路都不可用。因此我们需要对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩。熔断降级作为保护自身的手段,通常在客户端(调用端)进行配置。
Sentinel 熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。
当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出 DegradeException)。
Sentinel断路器是没有半开状态,半开的状态,系统自动去检测是否请求有异常,没有异常就关闭断路器恢复使用,有异常则继续打开断路器不可用,具体可以参考 hystrix。
官网:https://github.com/alibaba/Sentinel/wiki/%E7%86%94%E6%96%AD%E9%99%8D%E7%BA%A7
1)RT(平均响应时间,秒级)
平均响应时间 超出阈值且在时间窗口内通过的请求>=5,两个条件同时满足后触发降级
窗口期过后关闭断路器
RT最大4900(更大的需要通过-Dcsp.sentinel.statistic.max.rt=XXXX才能生效)
2)异常比例(秒级)
QPS >= 5且异常比例(秒级统计)超过阈值时,触发降级;时间窗口结束后,关闭降级
3)异常数(分钟级)
异常数(分钟统计)超过阈值时,触发降级;时间窗口结束后,关闭降级
1)平均响应时间RT
平均响应时间 (DEGRADE_GRADE_RT
):当 1s 内持续进入5个请求,平均响应时间(秒级)超过阈值(count,以 ms 为单位),那么在接下的时间窗口 (DegradeRule 中的 timeWindow,以 s 为单位)之内,对这个方法的调用都会自动地熔断(抛出 DegradeException)。
Sentinel 默认统计的RT上限是4900 ms, 超出此阈值的都会算作 4900ms,若需要修改此上限可以通过启动配置项
-Dcsp.sentinel.statistic.max.rt=xxx
来配置。
添加代码,
@GetMapping("/testD")
public String testD(){
//暂停几秒钟线程
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
log.info("testD 测试RT");
return "------testD";
}
Jmeter压力测试设置,1秒10个请求,
测试地址:http://localhost:8401/testD,发现服务降级
说明:一秒钟进来10个线程(大于5个)调用testD,希望200毫秒处理完本次任务,如果超过200毫秒还没处理完,在未来1秒钟的时间窗口内,断路器打开(保险丝跳闸)微服务不可用,保险丝跳闸断电了,停止jmeter,没有这么大的访问量了,断路器关闭(保险丝恢复),微服务恢复正常。
2)异常比例
异常比例 (DEGRADE_GRADE_EXCEPTION_RATIO
):当资源的每秒请求量 >= 5(可配置),并且每秒异常总数占通过量的比值超过阈值(DegradeRule 中的 count)之 后,资源进入降级状态,即在接下的时间窗口(DegradeRule 中的 timeWindow, 以 s 为单位)之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
添加业务代码,
@GetMapping("/testC")
public String testC()
{
log.info("testC 测试异常比例");
int age=10/0;
return "------testC";
}
配置降级规则和JMeter压测,
按照上述配置,访问接口:http://localhost:8401/testC
单独访问一次,必然来一次报错一次(int age = 10/0),调一次错一次;
开启jmeter后,直接高并发发送请求,多次调用达到我们的配置条件了。 Blocked by Sentinel (flow limiting)
断路器开启(保险丝跳闸),微服务不可用了,不再报错error而是服务降级了。
3)异常数 (DEGRADE_GRADE_EXCEPTION_COUNT
):当资源近1分钟的异常数目超过阈值之后会进行熔断。
NOTE:时间窗口一定要大于等于 60 秒 ;异常数按分钟来统计
添加业务代码,
@GetMapping("/testE")
public String testE()
{
log.info("testE 测试异常数");
int age=10/0;
return "------testE";
}
http://localhost:8401/testE,1-5次访问报错,因为除数不能为零,达到5次报错后,进入熔断后降级。
Blocked by Sentinel (flow limiting)
热点即经常访问的数据,很多时候我们希望统计或者限制某个热点数据中访问频次最高的TopN数据,并对其访问进行限流或者其它操作。
兜底方法fallback分为两种:系统默认和客户自定义,sentinel系统默认的提示:Blocked by Sentinel (flow limiting)
,类似hystrix,某个方法出问题了,就找对应的兜底降级方法? 从@HystrixCommand
到@SentinelResource
官网:https://github.com/alibaba/Sentinel/wiki/%E7%83%AD%E7%82%B9%E5%8F%82%E6%95%B0%E9%99%90%E6%B5%81
源码:com.alibaba.csp.sentinel.slots.block.BlockException
需求:
testHotKey
方法第一个参数只要QPS超过每秒1次,马上降级处理,执行自定义兜底方法deal_testHotKey
【第一步】添加业务代码
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey")
public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
@RequestParam(value = "p2",required = false) String p2){
return "----------testHotKey";
}
public String deal_testHotKey(String p1, String p2, BlockException exception){
return "____________deal_testHotKey____________";
}
NOTE:
@SentinelResource
处理的是Sentinel控制台配置的违规情况,有blockHandler方法配置的兜底处理;
int age = 10/0
,这个是java运行时报出的运行时异常RunTimeException
,@SentinelResource
不管
【第二步】配置热点规则
说明:
1)资源名为路径名或者
@SentinelResource
注解的value值2)限流模式只支持QPS模式,单机阀值以及统计窗口时长表示在此窗口时间超过阀值就限流。
3)
@SentinelResource
注解的方法,参数索引,0代表第一个参数,1代表第二个参数,以此类推
【第三步】测试
测试地址:
http://localhost:8401/testHotKey?p1=abc 服务降级
http://localhost:8401/testHotKey?p1=abc&p2=ddd 服务降级
http://localhost:8401/testHotKey?p2=abc
需求:当p1的值等于5时,它的阈值可以达到200;当p1不等于5的时候,阈值就是1。
NOTE:热点参数的注意点,参数必须是基本类型或者String
测试:
http://localhost:8401/testHotKey?p1=5 阈值可至200
http://localhost:8401/testHotKey?p1=3 阈值为1,直接限流
Sentinel系统自适应过载保护,从整体维度对应用入口流量进行控制,结合应用的 Load负载、CPU 使用率、总体平均 RT、入口 QPS 和并发线程数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
官网:https://github.com/alibaba/Sentinel/wiki/%E7%B3%BB%E7%BB%9F%E8%87%AA%E9%80%82%E5%BA%94%E9%99%90%E6%B5%81
系统保护规则是从应用级别的入口流量进行控制,从单台机器的 load负载、CPU 使用率、平均 RT、入口 QPS 和并发线程数等几个维度监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。应用全局配置
系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(EntryType.IN
),比如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。
系统规则支持以下的模式:
1)Load 自适应(仅对 Linux/Unix-like 机器生效):系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的 maxQps * minRt
估算得出。设定参考值一般是 CPU cores * 2.5
。
2)CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。
3)平均 RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
4)并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
5)入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。
添加业务代码
@RestController
public class RateLimitController {
@GetMapping("/byResource")
@SentinelResource(value = "byResource",blockHandler = "handleException")
public CommonResult byResource()
{
return new CommonResult(200,"按资源名称限流测试OK",new Payment(2023L,"serial001"));
}
public CommonResult handleException(BlockException exception)
{
return new CommonResult(444,exception.getClass().getCanonicalName()+"\t 服务不可用");
}
}
NOTE:关闭8401服务,Sentinel控制台流控规消失,临时性。
修改业务代码
@RestController
public class RateLimitController
{
@GetMapping("/rateLimit/byUrl")
@SentinelResource(value = "byUrl")
public CommonResult byUrl()
{
return new CommonResult(200,"按url限流测试OK",new Payment(2020L,"serial002"));
}
}
http://localhost:8401/rateLimit/byUrl,触发默认兜底方法,Blocked by Sentinel (flow limiting)
1)系统默认的,没有体现我们自己的业务要求。
2 )依照现有条件,自定义的处理方法又和业务代码耦合在一块,不直观。
3 )每个业务方法都添加一个兜底的,代码膨胀加剧。
4 )全局统一的处理方法没有体现。
需求:自定义全局统一的处理方法——fallback兜底方法
参考文档:https://github.com/alibaba/Sentinel/wiki/%E6%B3%A8%E8%A7%A3%E6%94%AF%E6%8C%81
【一】创建自定义限流处理类
public class CustomerBlockHandler {
public static CommonResult handleException1(BlockException exception){
return new CommonResult(4444,"自定义的限流处理信息......handleException1");
}
public static CommonResult handleException2(BlockException exception){
return new CommonResult(4444,"自定义的限流处理信息......handleException2");
}
}
NOTE:注解方式埋点不支持 private 方法。
【二】修改业务类
@GetMapping("/rateLimit/customerBlockHandler")
@SentinelResource(
value = "customerBlockHandler",
blockHandlerClass= CustomerBlockHandler.class,
blockHandler ="handleException2")
public CommonResult customerBlockHandler(){
return new CommonResult(200,"按客户自定义限流处理逻辑",new Payment(2023L,"serial003"));
}
【三】修改流控规则,
【四】测试地址:http://localhost:8401/rateLimit/customerBlockHandler
需求:
sentinel
整合ribbon+openFeign+fallback
新建服务提供者模块cloudalibaba-provider-payment9003
、cloudalibaba-provider-payment9004
以cloudalibaba-provider-payment9003
为例
【第一步】创建Module
cloudalibaba-provider-payment9003
【第二步】添加项目依赖
<dependencies>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>com.example.cloudgroupId>
<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>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>runtimescope>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
【第三步】创建application.yml配置文件
server:
port: 9003
spring:
application:
name: nacos-payment-provider
cloud:
nacos:
discovery:
server-addr: localhost:8848 #配置Nacos地址
management:
endpoints:
web:
exposure:
include: '*'
【第四步】创建启动类
@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<>();
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);
CommonResult<Payment> result = new CommonResult(200,"from mysql,serverPort: "+serverPort,payment);
return result;
}
}
【第六步】测试
测试地址1:http://localhost:9003/paymentSQL/1
测试地址2:http://localhost:9004/paymentSQL/1
【第一步】创建
新建服务消费者模块cloudalibaba-consumer-nacos-order84
【第二步】添加依赖
<dependencies>
<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>com.example.cloudgroupId>
<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>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>runtimescope>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
【第三步】创建application.yml配置文件
server:
port: 84
spring:
application:
name: nacos-order-consumer
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
#配置Sentinel dashboard地址
dashboard: localhost:8080
#默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
port: 8719
#消费者将要去访问的微服务名称(注册成功进nacos的微服务提供者)
service-url:
nacos-user-service: http://nacos-payment-provider
【第四步】创建启动类
@EnableDiscoveryClient
@SpringBootApplication
public class OrderNacosMain84
{
public static void main(String[] args) {
SpringApplication.run(OrderNacosMain84.class, args);
}
}
【第五步】创建业务类
配置类
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
controller
@RestController
@Slf4j
public class CircleBreakerController {
public static final String SERVICE_URL = "http://nacos-payment-provider";
@Autowired
private RestTemplate restTemplate;
@Autowired
PaymentFallbackService paymentFallbackService;
@Resource
private OrderService orderService;
@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")
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;
}
public CommonResult handlerFallback(@PathVariable Long id,Throwable e) {
Payment payment = new Payment(id,"null");
return new CommonResult<>(444,"兜底异常handlerFallback,exception内容 "+e.getMessage(),payment);
}
public CommonResult blockHandler(@PathVariable Long id, BlockException blockException) {
Payment payment = new Payment(id,"null");
return new CommonResult<>(445,"blockHandler-sentinel限流,无此流水: blockException "+blockException.getMessage(),payment);
}
}
总结:fallback负责业务异常;blockHandler负责在sentinel里面配置的降级限流
【第五步】测试
测试地址:http://localhost:84/consumer/fallback/1
测试情况:
1)没有任何配置
2)只配置fallback
3)只配置blockHandler
4)fallback和blockHandler都配置
需求:修改
cloudalibaba-consumer-nacos-order84
模块,84消费者调用提供者9003。
Feign组件一般是消费方
【第一步】添加依赖
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
【第二步】修改application.yml
# 激活Sentinel对Feign的支持
feign:
sentinel:
enabled: true
【第三步】启动类添加@EnableFeignClients
【第四步】修改业务类
定义注解+接口
@Component
@FeignClient(value="nacos-payment-provider",fallback = PaymentFallbackService.class)
public interface OrderService {
@GetMapping(value = "/paymentSQL/{id}")
public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
}
自定义fallback兜底方法
@Component
public class PaymentFallbackService implements OrderService {
@Override
public CommonResult<Payment> paymentSQL(Long id) {
return new CommonResult<>(444,"服务降级返回,没有该流水信息",new Payment(id, "errorSerial......"));
}
}
controller
@RestController
@Slf4j
public class CircleBreakerController {
@Autowired
private OrderService orderService;
@GetMapping(value = "/consumer/openfeign/{id}")
public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id)
{
if(id == 4)
{
throw new RuntimeException("没有该id");
}
return orderService.paymentSQL(id);
}
}
【第五步】测试
接口地址:http://localhost:84/consumer/openfeign/1
测试84调用9003,关闭9003微服务提供者,84消费方自动降级,不会一直等待
问题引入:一旦重启应用,sentinel规则将消失,生产环境需要将配置规则进行持久化。
规则持久化策略:将限流配置规则持久化进Nacos保存,只要刷新8401某个rest地址,sentinel控制台的流控规则就能看到,只要Nacos里面的配置不删除,针对8401上sentinel上的流控规则持续有效。
修改cloudalibaba-sentinel-service8401
模块
【第一步】添加依赖
<dependency>
<groupId>com.alibaba.cspgroupId>
<artifactId>sentinel-datasource-nacosartifactId>
dependency>
【第二步】修改application.yml
配置
spring:
cloud:
sentinel:
datasource:
ds1:
nacos:
server-addr: localhost:8848
dataId: cloudalibaba-sentinel-service
groupId: DEFAULT_GROUP
data-type: json
rule-type: flow
【第三步】添加Nacos业务规则配置
[
{
"resource": "/rateLimit/byUrl",
"limitApp": "default",
"grade": 1,
"count": 1,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
说明:
1)resource:资源名称;
2)limitApp:来源应用;
3)grade:阈值类型,0表示线程数,1表示QPS;
4)count:单机阈值;
5)strategy:流控模式,0表示直接,1表示关联,2表示链路;
6)controlBehavior:流控效果,0表示快速失败,1表示Warm Up,2表示排队等待;
7)clusterMode:是否集群。
【第四步】测试
启动8401后,刷新sentinel,发现业务规则有了,访问http://localhost:8401/rateLimit/byUrl,默认fallback,Blocked by Sentinel (flow limiting)
停止8401再看sentinel,流控规则消失了
重新启动8401再看sentinel,多次调用请求接口http://localhost:8401/rateLimit/byUrl,流控规则出现,持久化测试通过。