我是靠谱客的博主 大胆猎豹,这篇文章主要介绍SpringCloud Alibaba第十三章,升级篇,服务降级、熔断和限流Sentinel一、Sentinel概述二、Sentinel控制台安装三、Sentinel案例,现在分享给大家,希望可以做个参考。

SpringCloud Alibaba第十三章,升级篇,服务降级、熔断和限流Sentinel

一、Sentinel概述

1、Sentinel是什么

复制代码
1
2
3
4
5
6
7
8
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。 一句话概括:sentinel即Hystrix的替代品 官网: https://sentinelguard.io/zh-cn/ 下载:https://github.com/alibaba/Sentinel/releases

在这里插入图片描述

2、Sentinel基本概念

2.1、资源:

复制代码
1
2
3
4
5
6
资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调 用的其它应用提供的服务,甚至可以是一段代码。在接下来的文档中,我们都会用资源来描述代码块。 只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名, URL,甚至服务名称作为资源名来标示资源。

2.2、规则:

复制代码
1
2
围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。

2.3、流量控制:

复制代码
1
2
3
4
5
6
7
8
9
10
流量控制在网络传输中是一个常用的概念,它用于调整网络包的发送数据。然而,从系统稳定性角度考虑,在处理请求的速度 上,也有非常多的讲究。任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们需要根据系统的处理能 力对流量进行控制。Sentinel 作为一个调配器,可以根据需要把随机的请求调整成合适的形状. 流量控制有一下几个角度: 1、资源的调用关系,例如资源的调用链路,资源和资源之间的关系; 2、运行指标,例如 QPS、线程池、系统负载等; 3、控制的效果,例如直接限流、冷启动、排队等。

2.4、熔断降级:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
降低调用链路中的不稳定资源也是 Sentinel 的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳 定,最终会导致请求发生堆积。这个问题和 Hystrix 里面描述的问题是一样的。 Sentinel 和 Hystrix 的原则是一致的: 当调用链路中某个资源出现不稳定,例如,表现为 timeout,异常比例升高的 时候,则对这个资源的调用进行限制,并让请求快速失败,避免影响到其它的资源,最终产生雪崩的效果。 Sentinel和Hystrix在限制手段上,采取了不一样的方法: 1、Hystrix通过线程池的方式: Hystrix 通过线程池的方式,来对依赖进行了隔离。 2、Sentinel 对这个问题采取了两种手段: a、通过并发线程数进行限制 b、通过响应时间对资源进行降级

2.5、系统负载保护:

复制代码
1
2
3
4
5
6
7
8
Sentinel 同时对系统的维度提供保护。防止雪崩,是系统防护中重要的一环。当系统负载较高的时候,如果还持续让请求 进入,可能会导致系统崩溃,无法响应。在集群环境下,网络负载均衡会把本应这台机器承载的流量转发到其它的机器上去。 如果这个时候其它的机器也处在一个边缘状态的时候,这个增加的流量就会导致这台机器也崩溃,最后导致整个集群不可用。 针对这个情况,Sentinel 提供了对应的保护机制,让系统的入口流量和系统的负载达到一个平衡,保证系统在能力范围之 内处理最多的请求。

二、Sentinel控制台安装

复制代码
1
2
3
4
Sentinel分为两个部分: 1、核心库 2、控制台dashboard,基于Springboot开发,打包后可直接运行,不需要Tomcat等额外的容器

下载:

复制代码
1
2
https://github.com/alibaba/Sentinel/releases

运行:

复制代码
1
2
3
4
Sentinel Dashboard默认的端口是8080 java -jar sentinel-dashboard-1.7.0.jar

访问:

复制代码
1
2
3
4
http://localhost:8080/ 账号:sentinel 密码:sentinel

三、Sentinel案例

3.1、初始化演示工程

创建cloudalibaba-sentinel-service-8401

复制代码
1
2
3
4
5
6
7
8
9
<parent> <artifactId>cloud_2020</artifactId> <groupId>com.lee.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloudalibaba-sentinel-service-8401</artifactId>

POM

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>cloud_2020</artifactId> <groupId>com.lee.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloudalibaba-sentinel-service-8401</artifactId> <dependencies> <!--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> <!--SpringCloud ailibaba nacos --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>com.lee.springcloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </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> </project>

application.yml

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
server: port: 8401 spring: application: name: cloudalibaba-sentinel-service cloud: nacos: discovery: server-addr: localhost:8848 sentinel: transport: dashboard: localhost:8080 port: 8719 #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口 management: endpoints: web: exposure: include: '*'

主启动类:

复制代码
1
2
3
4
5
6
7
8
9
@SpringBootApplication @EnableDiscoveryClient public class SentinelMain8401 { public static void main(String[] args) { SpringApplication.run(SentinelMain8401.class,args); } }

业务类:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Slf4j @RestController public class FlowLimitController { @GetMapping("/testA") public String testA(){ return "=======>testA"; } @GetMapping("/testB") public String testB(){ return "=======>testB"; } }

测试:

复制代码
1
2
3
4
5
6
7
8
1、启动nacos server、Sentinel-Dashboard、CloudAlibaba-sentinel-service-8401 2、查看sentinel控制台 http://localhost:8080/ 结果:空空如也 (因为:Sentinel采用的是懒加载模式) 3、浏览:http://localhost:8401/testA和http://localhost:8401/testB 4、再查看sentinel控制台 http://localhost:8080/

在这里插入图片描述

3.2、流控规则

复制代码
1
2
3
4
5
6
7
8
9
10
资源新增流控,可以通过两个地方来添加: 1、簇点链路-点击”+流控“ 2、流控规则-点击"新增流控规则" 阈值类型: QPS:系统每秒钟处理完成的请求次数 (QPS是在请求进入应用之前就处理,线程数是在请求进入应用之后处理)

3.2.1、流控模式

复制代码
1
2
流控3种模式分为:直接、关联、链路

3.2.1.1、直接

在这里插入图片描述

测试:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
1、直接的配置如上 2、每秒访问一次http://localhost:8401/testA 正常 3、每秒多次快速的访问http://localhost:8401/testA Blocked by Sentinel (flow limiting) (当再次恢复每秒1次的访问频率时,又可正常访问) 思考: 访问频次不符合配置规则后直接显示sentinel的默认处理Blocked by Sentinel,我们如何自定义规则不匹配的情况呢? (后续会介绍:@SentinelResource去做方法的兜底处理,类似Hystrix的@HystrixCommand)

3.2.1.2、关联

复制代码
1
2
什么是关联?即当与testA相关的资源testB达到阈值时,就挂testA

在这里插入图片描述

测试:

复制代码
1
2
3
4
5
6
7
8
1、配置规则如上 2、postman模拟并发密集的访问http://localhost:8401/testB 3、浏览器访问http://localhost:8401/testA 结果:Blocked by Sentinel (flow limiting) (当对testB密集访问停止后,testA访问恢复正常)

在这里插入图片描述

3.2.1.3、链路

新增代码:service

复制代码
1
2
3
4
5
6
7
8
9
10
11
@Slf4j @Service public class FlowLimitService { @SentinelResource("findOrder") public String findOrder(){ log.info("----order----"); return "order"; } }

controller

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Slf4j @RestController public class FlowLimitController { @Resource private FlowLimitService flowLimitService; @GetMapping("/testA") public String testA(){ flowLimitService.findOrder(); return "=======>testA"; } @GetMapping("/testB") public String testB(){ flowLimitService.findOrder(); return "=======>testB"; } }

配置规则:

在这里插入图片描述

复制代码
1
2
3
4
5
6
7
8
1、配置规则如上 2、快速访问http://localhost:8401/testA 结果: ###############################有待确认############# 快速访问http://localhost:8401/testB 结果: ###############################有待确认#############

3.2.2、流控效果

3.2.2.1、快速失败

复制代码
1
2
3
4
5
源码: com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController 上面写流控模式的时候已经展示了效果,不符合配置的时候,快速做出对应的反映,如

3.2.2.2、Warn Up预热

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
源码: com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController 公式: 阈值除以coldFactor(默认为3),经过预热时长后才会达到阈值 限流-冷启动: 当流量突然增大的时候,我们常常会希望系统从空闲状态到繁忙状态的切换的时间长一些。即如果系统在此之前长期处于空闲 的状态,我们希望处理请求的数量是缓步的增多,经过预期的时间以后,到达系统处理请求个数的最大值。Warm Up(冷启 动,预热)模式就是为了实现这个目的的。 应用场景: 秒杀系统在开启的瞬间,会有很多流量上来,会把系统打死,预热方式就是为了保护系统,可以慢慢的把流量放进来。 慢慢的把阈值增长到设定的阈值、

在这里插入图片描述

复制代码
1
2
3
配置解读: 系统初始化的阈值为10/3约等于3,即阈值刚开始为3.然后过了5秒后阈值才逐渐升到10

3.2.2.3、排队等待

复制代码
1
2
3
4
5
6
7
源码: com.alibaba.csp.sentinel.slots.block.flow.controller.RateLimiterController 匀速排队,阈值必须设置为QPS。 匀速排队会严格控制请求通过的时间间隔。也即是让请求以均匀的速度通过,对应的是漏桶算法。(类似消息队列)

在这里插入图片描述

复制代码
1
2
3
配置解读: /testB每秒1次请求,超过的话就排队等待。等待的超时时间是20000ms

3.3、降级规则

复制代码
1
2
降级规则包括:RT、异常比例、异常数

3.3.1、RT平均响应时间

复制代码
1
2
3
4
5
6
7
RT平均响应时间: 当1s内持续进入5个请求,对应时刻的平均响应时间均超过阈值,那么在接下的时间窗口之内,对这个方法的调用都会自动地 熔断(抛出DegradeException). Sentinel的默认RT上限是4900ms,超出此阈值的都会算作4900ms。若需要变更此上线可以通过: -Dcsp.sentinel.statistic.max.rt=xxx来配置

在这里插入图片描述

新增代码:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
@GetMapping("/testD") public String testD() { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } log.info("testD 测试RT"); return "=======>testD"; }

配置

在这里插入图片描述

测试:

在这里插入图片描述

复制代码
1
2
3
4
5
6
7
8
9
10
如上JMeter创建1s中10个线程的访问去请求testD. 然后再浏览器上访问http://localhost:8401/testD 结果: Blocked by Sentinel (flow limiting) (配置中,我们希望200毫秒处理完这次任务,如果200毫秒还没处理完,在未来1s的时间窗口内,断路器打开,微服务不可用) (当我们停止JMeter测试后,没这么大访问量了,断路器关闭,微服务恢复。)

3.3.2、异常比例

复制代码
1
2
3
4
异常比例: 当资源的每秒请求量>=5,并且每秒异常总数占通过量的比值超过阈值之后,资源进入降级状态,即在接下来的时间窗口之 内,对这个方法的调用都会自动返回。

在这里插入图片描述

新增代码:

复制代码
1
2
3
4
5
6
7
8
@GetMapping("/testE") public String testE() { log.info("testE 测试RT"); int age = 10/0; return "------testE"; }

配置规则:

在这里插入图片描述

测试:

复制代码
1
2
3
4
5
6
7
8
9
10
JMeter压测testE,每秒10个线程 浏览器访问:http://localhost:8401/testE 结果:不是报错,而是Blocked by Sentinel (flow limiting) 结论: 开启JMeter后,直接高并发发送请求,多次调用达到了我们的配置条件。断路器开启,微服务不可用,不再报错error而是 进入服务降级

3.3.3、异常数

复制代码
1
2
3
4
异常数: 当资源近1分钟的异常数目超过阈值之后进入熔断,这个统计时间窗口是分钟级别的,若timewindow小于60s,则结束熔断状 态后仍可能再次进入熔断状态

在这里插入图片描述

新增代码:

复制代码
1
2
3
4
5
6
7
8
@GetMapping("/testF") public String testF() { log.info("testF 测试异常数"); int age = 10/0; return "------testF 测试异常数"; }

配置规则如下:

在这里插入图片描述

复制代码
1
2
3
4
5
浏览器访问:http://localhost:8401/testF 前5次报错,走Error 之后报:Blocked by Sentinel (flow limiting) 61s后,服务熔断解除,走Error

3.4、热点KEY限流

3.4.1、普通配置

复制代码
1
2
3
何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限 制。

之前的case,限流出现问题后,都是Sentinel的默认提示:Blocked by Sentinel (flow limiting)

我们将使用@SentinelResource,类似Hystrix的@HystrixCommand。当方法出现问题后就找对应的兜底方法返回。

新增方法如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
@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) { //int age = 10/0; return "------testHotKey"; } //兜底方法 public String deal_testHotKey (String p1, String p2, BlockException exception){ return "------deal_testHotKey,o(╥﹏╥)o"; }

配置规则如下:

在这里插入图片描述

测试:

复制代码
1
2
3
4
5
6
7
8
9
10
11
快速访问:http://localhost:8401/testHotKey 结果:------testHotKey 快速访问:http://localhost:8401/testHotKey?p1=abc 结果:------deal_testHotKey,o(╥﹏╥)o 快速访问:http://localhost:8401/testHotKey?p2=123 结果:------testHotKey 快速访问:http://localhost:8401/testHotKey?p1=abc&p2=123 结果:------deal_testHotKey,o(╥﹏╥)o 如果不快速访问,达不到阈值时,也只会返回------testHotKey

3.4.2、参数例外:

我们有时候期望当P1参数为某个特殊值时,它的限流值和平时不一样,假如当P1==5时,期望它的阈值为200。

在这里插入图片描述

测试:

复制代码
1
2
3
4
5
6
1、浏览器快速访问:http://localhost:8401/testHotKey?p1=5 返回:------testHotKey 2、浏览器快速访问:http://localhost:8401/testHotKey?p1=3 返回:------deal_testHotKey,o(╥﹏╥)o 注意:参数必须是基础数据类型

3.5、系统规则

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
系统保护规则是从应用级别的入口流量进行控制,从单台机器的 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: 当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。 3、平均 RT: 当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。 4、并发线程数: 当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。 5、入口 QPS: 当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。

3.6、@SentinelResource

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
@SentinelResource: 类似Hystrix的@HystrixCommand,做兜底服务自定义 其中blockXXXX是处理:配置违规的 @blockHandlerClass 处理类 @blockHandler 处理类下的处理方法 fallback:处理异常,做服务降级的 exceptionToIgnore:忽略异常 【程序异常和违规同时发生优先执行blockHandler】

3.6.1、按资源名称限流

新增业务类RateLimitController:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Slf4j @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
2
3
4
5
6
7
8
9
10
11
上述配置解析: 表示1秒钟内查询次数大于1,就限流跑到我们自定义的方法 1、1s访问一次:http://localhost:8401/byResource 结果:{"code":200,"message":"按资源名称限流测试OK","data":{"id":2020,"serial":"serial001"}} 2、1s内快速多次访问:http://localhost:8401/byResource 结果:{"code":444,"message":"com.alibaba.csp.sentinel.slots.block.flow.FlowExceptiont 服务不可用","data":null} 根据资源名称限流,会优先返回我们自定义的处理信息,没有自定义的返回Sentinel默认限流处理信息

3.6.2、按URL地址限流

新增方法:

复制代码
1
2
3
4
5
6
7
8
9
10
11
@GetMapping("/rateLimit/byUrl") @SentinelResource(value = "byUrl",blockHandler = "byUrlHandler") public CommonResult byUrl() { return new CommonResult(200,"按url限流测试OK",new Payment(2020L,"serial002")); } public CommonResult byUrlHandler(BlockException exception){ return new CommonResult(444,exception.getClass().getCanonicalName()+"t 服务不可用"); }

新增配置:

在这里插入图片描述

测试:

复制代码
1
2
3
4
5
6
7
8
9
10
1、1s访问一次:http://localhost:8401/rateLimit/byUrl 结果: {"code":200,"message":"按url限流测试OK","data":{"id":2020,"serial":"serial002"}} 2、1s内快速访问:http://localhost:8401/rateLimit/byUrl 结果: Blocked by Sentinel (flow limiting) 根据url地址限流返回的是Sentinel自带的默认限流处理信息

3.6.3、优化

以上一个方法新增一个对应的处理限流方法,代码冗余且和业务混杂,我们可以将处理方法提出来做单独处理

新增一个handler:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class CustomerBlockHandler { //注意---这里必须是static且不能为private public static CommonResult handlerException(BlockException exception) { return new CommonResult(4444,"按客戶自定义,global handlerException----1"); } public static CommonResult handlerException2(BlockException exception) { return new CommonResult(4444,"按客戶自定义,global handlerException----2"); } }

业务类新增方法:

复制代码
1
2
3
4
5
6
7
8
9
@GetMapping("/rateLimit/customerBlockHandler") @SentinelResource(value = "customerBlockHandler", blockHandlerClass = CustomerBlockHandler.class, blockHandler = "handlerException") public CommonResult customerBlockHandler() { return new CommonResult(200,"按客戶自定义",new Payment(2020L,"serial003")); }

新增对应的配置,然后测试:

复制代码
1
2
3
4
5
1s内多次快速的访问:http://localhost:8401/rateLimit/customerBlockHandler 结果: {"code":4444,"message":"按客戶自定义,global handlerException----1","data":null}

3.7、Sentinel与Ribbon和Feign的整合

3.7.1、Sentinel与Ribbon

3.7.1.1、创建cloudalibaba-provider-payment-9004和9005

复制代码
1
2
3
4
5
6
7
8
<parent> <artifactId>cloud_2020</artifactId> <groupId>com.lee.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloudalibaba-provider-payment-9004</artifactId>

pom

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>cloud_2020</artifactId> <groupId>com.lee.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloudalibaba-provider-payment-9004</artifactId> <dependencies> <!--SpringCloud ailibaba nacos --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity --> <groupId>com.lee.springcloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency> <!-- SpringBoot整合Web组件 --> <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>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> </project>

application.yml

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server: port: 9004 spring: application: name: nacos-payment-provider cloud: nacos: discovery: server-addr: localhost:8848 #配置Nacos地址 management: endpoints: web: exposure: include: '*'

主启动类

复制代码
1
2
3
4
5
6
7
8
9
@SpringBootApplication @EnableDiscoveryClient//服务发现 public class PaymentMain9004 { public static void main(String[] args) { SpringApplication.run(PaymentMain9004.class,args); } }

业务类

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Slf4j @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,"aaa")); hashMap.put(2L,new Payment(2L,"bbb")); hashMap.put(3L,new Payment(3L,"ccc")); } @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; } }

3.7.1.2、创建cloudalibaba-consumer-order-84

复制代码
1
2
3
4
5
6
7
8
<parent> <artifactId>cloud_2020</artifactId> <groupId>com.lee.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloudalibaba-consumer-order-84</artifactId>

POM

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>cloud_2020</artifactId> <groupId>com.lee.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloudalibaba-consumer-order-84</artifactId> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</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.lee.springcloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency> <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> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </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> </project>

application.yml

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
server: port: 84 spring: application: name: nacos-order-consumer cloud: nacos: discovery: server-addr: localhost:8848 sentinel: transport: dashboard: localhost:8080 port: 8719 service-url: nacos-user-service: http://nacos-payment-provider

主启动类

复制代码
1
2
3
4
5
6
7
8
9
10
@EnableDiscoveryClient @SpringBootApplication @EnableFeignClients public class ConsumerOrderNacos84 { public static void main(String[] args) { SpringApplication.run(ConsumerOrderNacos84.class,args); } }

配置类

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
@Configuration public class ApplicationContextConfig { @Bean @LoadBalanced public RestTemplate getRestTemplate() { return new RestTemplate(); } }

业务类

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
@Slf4j @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 handlerFallback(@PathVariable Long id,Throwable e) { Payment payment = new Payment(id,"null"); return new CommonResult<>(444,"兜底异常handlerFallback,exception内容 "+e.getMessage(),payment); } //blockHandler public CommonResult blockHandler(@PathVariable Long id, BlockException blockException) { Payment payment = new Payment(id,"null"); return new CommonResult<>(445,"blockHandler-sentinel限流,无此流水: blockException "+blockException.getMessage(),payment); } }

3.7.1.3、测试:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
1、启动nacos-server、sentinel-server、cloudalibaba-provider-payment-9004、9005、 cloudalibaba-consumer-order-84 #############测试一############ 2、浏览器访问:http://localhost:84/consumer/fallback/1 结果: {"code":200,"message":"from mysql,serverPort: 9004","data":{"id":1,"serial":"aaa"}} {"code":200,"message":"from mysql,serverPort: 9005","data":{"id":1,"serial":"aaa"}} 两个结果来回切换 3、浏览器访问:http://localhost:84/consumer/fallback/4 结果: Whitelabel Error Page #############测试二############## 4、consumer-84业务类放开注解@SentinelResource(value = "fallback",fallback = "handlerFallback")//fallback只负责业务异常 5、浏览器访问:http://localhost:84/consumer/fallback/4 结果: {"code":444,"message":"兜底异常handlerFallback,exception内容 IllegalArgumentException,非法参数异常....","data":{"id":4,"serial":"null"}} ##############测试三############ 6、consumer-84业务类放开注解@SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler只负责sentinel控制台配置违规 7、且sentinel控制台新增fallback的降级策略 新增降级: 资源名:fallback 策略:异常数 异常数:2 时间窗口:2 8、浏览器访问:http://localhost:84/consumer/fallback/2 结果:正常 浏览器访问:http://localhost:84/consumer/fallback/4 结果:Whitelabel Error Page 快速多次访问:http://localhost:84/consumer/fallback/4 结果:{"code":445,"message":"blockHandler-sentinel限流,无此流水: blockException null","data":{"id":4,"serial":"null"}} ##################测试四############ 9、consumer-84业务类放开注解@SentinelResource(value = "fallback", fallback = "handlerFallback", blockHandler = "blockHandler",exceptionsToIgnore = {IllegalArgumentException.class}) 10、浏览器访问:http://localhost:84/consumer/fallback/4 结果:Whitelabel Error Page 浏览器访问:http://localhost:84/consumer/fallback/5 结果:{"code":444,"message":"兜底异常handlerFallback,exception内容 NullPointerException,该ID没有对应记录,空指针异常","data":{"id":5,"serial":"null"}} 结论: @blockHandlerClass 处理类 @blockHandler 处理类下的处理方法 fallback:处理异常,做服务降级的 exceptionToIgnore:忽略异常

3.7.2、Sentinel与OpenFeign

修改module:cloudalibaba-consumer-order-84

POM新增(上面创建的时候就已增加过了)

复制代码
1
2
3
4
5
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>

yml新增:

复制代码
1
2
3
4
5
#对Feign的支持 feign: sentinel: enabled: true

新增feign对应的接口:paymentService

复制代码
1
2
3
4
5
6
7
8
@FeignClient(value = "nacos-payment-provider",fallback = PaymentFallbackService.class) public interface PaymentService { @GetMapping(value = "/paymentSQL/{id}") public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id); }

新增feign接口的对应的服务降级类:PaymentFallbackService

复制代码
1
2
3
4
5
6
7
8
9
10
@Component public class PaymentFallbackService implements PaymentService { @Override public CommonResult<Payment> paymentSQL(Long id) { return new CommonResult<>(44444,"服务降级返回,---PaymentFallbackService",new Payment(id,"errorSerial")); } }

新增controller:OrderController

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Slf4j @RestController public class OrderController { // OpenFeign @Resource private PaymentService paymentService; @GetMapping(value = "/consumer/feign/paymentSQL/{id}") public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id) { return paymentService.paymentSQL(id); } }

主启动类新增注解:

复制代码
1
2
@EnableFeignClients

测试:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
1、启动nacos-server、sentinel-server、cloudalibaba-provider-payment-9004、9005、 cloudalibaba-consumer-order-84 2、浏览器访问:http://localhost:84/consumer/feign/paymentSQL/5 结果: {"code":200,"message":"from mysql,serverPort: 9005","data":null} 4、此时关闭cloudalibaba-provider-payment-9004、9005两个微服务,重新访问 结果: {"code":44444,"message":"服务降级返回,---PaymentFallbackService","data":{"id":5,"serial":"errorSerial"}}

3.8、Sentinel规则持久化

//TODO 以后再单独列出文章来写

最后

以上就是大胆猎豹最近收集整理的关于SpringCloud Alibaba第十三章,升级篇,服务降级、熔断和限流Sentinel一、Sentinel概述二、Sentinel控制台安装三、Sentinel案例的全部内容,更多相关SpringCloud内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(60)

评论列表共有 0 条评论

立即
投稿
返回
顶部