文章目录
SpringCloud Alibaba:
官方学习文档(中文): https://spring-cloud-alibaba-group.github.io/github-pages/2022/zh-cn/2022.0.0.0-RC2.html
微服务的中间件介绍与使用
微服务架构体系图:
依赖版本补充
下面所有代码中的依赖版本如下:
<properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <hutool.version>5.8.22</hutool.version> <lombok.version>1.18.26</lombok.version> <druid.version>1.1.20</druid.version> <mybatis.springboot.version>3.0.2</mybatis.springboot.version> <mysql.version>8.0.11</mysql.version> <swagger3.version>2.2.0</swagger3.version> <mapper.version>4.2.3</mapper.version> <fastjson2.version>2.0.40</fastjson2.version> <persistence-api.version>1.0.2</persistence-api.version> <spring.boot.test.version>3.1.5</spring.boot.test.version> <spring.boot.version>3.2.0</spring.boot.version> <spring.cloud.version>2023.0.0</spring.cloud.version> <spring.cloud.alibaba.version>2023.0.0.0-RC1</spring.cloud.alibaba.version> <knife4j-openapi3.version>4.4.0</knife4j-openapi3.version> </properties>
Sentinel:
Sentinel是用来应对 高并发 的情况,这里的概念和前文章 《springCloud/Alibaba常用中间件》中的LoadBalancer 相似,这里就不多讲了。
与 Resilience4j 它不同的是 Sentinel 有图形化界面进行动态的操作,使得操作便捷方便
1、下载-运行:Sentinel(1.8.6)
下载sentinel:
官方下载链接:https://github.com/alibaba/Sentinel/releases (这里在官网上下载可能会很慢,可以使用下面的网盘链接)
网盘链接: https://pan.baidu.com/s/1UtS7ltnSeKKwz1nkNvwBGw?pwd=chyb 提取码: chyb
运行:Sentinel
到sentinel的jar包目录下运行
sentinel-dashboard-1.8.6.jar -jar
,这里的jar包名称根据实际名称来
测试:打开网址http://localhost:8080(默认启动网址)
默认登录账号密码都是:sentinel
2、流控规则
sentinel中的流控模式有:直接、并联、链路。其中搭配中流控效果( 快速失败、Warm Up、排队等待 )可以应对大部分的限流操作
① 公共的测试代码以及需要使用的测试Jmeter
1、创建model导入依赖
<dependencies>
<!--SpringCloud ailibaba sentinel-datasource-nacos -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<!--SpringCloud alibaba sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--nacos-discovery-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--SpringBoot通用依赖模块-->
<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>
<!--hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.28</version>
<scope>provided</scope>
</dependency>
<!--test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2、修改配文件(application.yml)和启动类
server:
port: 8402
spring:
application:
name: cloudAlibaba-sentinelTest-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
port: 8719 #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
dashboard: localhost:8080 #sentinel的地址
@SpringBootApplication
@EnableDiscoveryClient
public class Main8402 {
public static void main(String[] args) {
SpringApplication.run(Main8402.class, args);
}
}
3、创建测试controller类
@RestController
/*流量限制控制器*/
public class FlowLimitController {
@GetMapping("/testA")
public String testA() {
return "------testA";
}
@GetMapping("/testB")
public String testB() {
return "------testB";
}
}
4、测试
请求一下http://localhost:8402/testB
或者 http://localhost:8402/testA
注意:这里一定要请求一下,否则可能不会显示,因为sentinel是一个 懒加载 要是没有请求的话它是不会自动取进行监测的
然后在去sentinel中的主页就可以看到有服务了且在实时监测中有两个请求
性能测试Jmeter下载
JMeter下载及安装(附插件及中文包超详细)
①、流控模式
1. 直接:
当接口达到限流条件的话,直接开启 限流(也就是相当于开启断路器中的 OPEN状态 )
列如:配置/testA当在一秒内超过两次以上就直接开启 限流
开始配置:
QPS(Queries Per Second):每秒请求数
测试当访问/testA过快时便会
Blocked by Sentinel(flow limiting)
2. 并联:
当某一个接口达到限流条件时,指定关联的那一个接口开启 限流
列如:配置/testB当在一秒内超过两次以上就开启/testA的 限流
测试:当访问/testB达到限流条件时,访问testA
3. 链路:
根据某一个资源的请求路径进行设置 流控规则
这里为了需要使用注解@SentinelResource大家先用着,下面在单独领出来进行解释
修改测试代码:
application.yml
#....
# spring.cloud.sentinel.web-context-unify
web-context-unify: false # controller层的方法对service层调用不认为是同一个根链路
controller
@RestController
/*流量限制控制器*/
public class FlowLimitController {
@Resource
private FlowLimitService flowLimitService;
@GetMapping("/testC")
public String testC() {
flowLimitService.common();
return "------testC";
}
@GetMapping("/testD")
public String testD() {
flowLimitService.common();
return "------testD";
}
}
在新建一个service层
@Service
public class FlowLimitService {
/*这里的value可以理解为资源名,只要接口中有使用的这个接口都可以直接使用这个作为资源进行统一设置限流规则*/
@SentinelResource(value = "common")
public void common() {
System.out.println("------FlowLimitService come in");
}
}
配置Sentinel(配置之前先将/testC和/testD请求一下)
测试:快速请求/testC和/testD查看请求情况
当以/testC进行请求时会有一个一秒QPS只有一次的规则限制
②、流控效果
1. 快速失败
当违反流控返回Sentinel中默认的流控处理:
Blocked by Sentinel (flow limiting)
(这里后面也是可以进行修改的)
这里了就不演示了,上面的测试都是使用的这个
2. Warm Up(预热处理)
Warm Up 状态的触发依赖于 冷启动阶段的流量控制规则配置,通过动态调整阈值实现流量的平滑过渡。[简单来说就是当很久都没有请求时,面对突然的请求会触发预热处理]
在 预热时长 期间内会根据 coldFactor(冷因子【默认是3】) 和QPS的 threshold(单机阀值) , 单机阀值为:
threshold/coldFactor
例如:一直请求知道预热时长结束,就会发现不会再出发 流控 了,当然也不排除请求过快,1秒10次也会触发
预热时只会放出:10(单机阀值)/3(冷因子),时长为:10s
3. 排队等待
当 QPS 达到阀值时,后米的请求不会直接挂掉,而是会进入到排队等待~ms,当过滤时长之后,还没有请求到的话便会才会挂掉
简单的说:QPS 超阈值时,请求进入队列等待;按固定间隔时间放行请求;超时未处理的请求会被拒绝。
优点是:这种机制能在保护系统的同时,减少请求的直接丢弃,适用于需要平滑处理流量的高并发场景。
列如:
扩展:所用的核心算法是 漏桶算法 (可以参考:《springCloud/Alibaba常用中间件》## 标题文章下的CircuitBreaker断路器-Resilience4j-ratelimit(限流)
目录)
③、并发线程数
控制统一时间的线程数,当超过固定值时便会进行 限流
例如:
此时使用Jmeter来帮助我们模拟并发线程的情况
启动之后在访问http://localhost/testA 则基本上不会请求成功
但是要是不开启Jmeter只有一个请求量时,不管你的请求速度有多块都不会限流
3、熔断规则
基础测试代码
@RestController
/*测试熔断规则*/
public class CircuitBreakerController {
@GetMapping("/testF")
public String testF() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "----------testF";
}
@GetMapping("/testG")
public String testG() {
int a = 1 / 0;
return "----------testF";
}
}
①、慢调用比留策略
根据你所定义的 根据指定 统计时长 内的指定的 最小请求数,去判断有多少慢调用(依据为:最大 RT),
最后计算比例是否大于 比例阈值,大于则进入熔断,经历 熔断时长 过后则会进入 HALF-OPEN(半开启状态)…(这里参考前面文章的CircuitBreaker断路器概念)
例如下面的Sentinel配置:
1000ms内请求大于5个,且慢调用(请求时长超过200ms的都视为慢调用)的比例超过0.1,则进入熔断且熔断时长为5s,
之后就是进入 HALF-OPEN(半开启状态)
名词解释:
- 调用:一个请求发送到服务器,服务器给与响应,一个响应就是一个调用。
- 最大RT:即最大的响应时间,指系统对请求作出响应的业务处理时间。
- 慢调用:处理业务逻辑的实际时间>设置的最大RT时间,这个调用叫做慢调用。
- 慢调用比例:在所以调用中,慢调用占有实际的比例=慢调用次数➗总调用次数
- 比例阈值:自己设定的 , 比例阈值=慢调用次数➗调用次数
- 统计时长:时间的判断依据
- 最小请求数:设置的调用最小请求数,上图比如1秒钟打进来10个线程(大于我们配置的5个了)调用被触发
测试:这时我们可以使用浏览器访问搭配Jmeter进行测试访问:http://localhost:8402/testF
②、异常比例策略
这里就是根据异常的比例进行判断是否熔断和慢调用比例策略原理差不多
例如下面的Sentinel配置:
1000ms内请求数大于5个,且一异常比例大于0.1,则进入熔断…
测试:
注意这里要区分一下,报错页面和熔断之后的页面
③、异常数策略
当异常数达到一定的数量的时候进入熔断…
例如下面的Sentinel配置:
1000ms内请求数大于5个,且一异常数大于1个…
@SentinelResource注解
它可以指定 限流返回处理 和 服务降级处理
- 限流返回处理: 是指当被限流(如熔断、流控)
之后返回的值,如Sentinel中默认返回的值为:Blocked by Sentinel (flow limiting)
- 服务降级处理: 当方法抛出 业务异常(非 Sentinel 拦截的异常)时,返回自定义的降级响应。
代码测试
@RestController
public class testSentinelResourceController {
@SentinelResource(
/*资源名*/
value = "testAnn",
/*指定限流返回处理的方法名*/
blockHandler = "block",
/*指定服务降级处理的方法名*/
fallback = "testFallback")
@GetMapping("/testH/{id}")
public String testH(@PathVariable("id") Integer id) {
if (id == 0) {
throw new RuntimeException("id 不可以为零");
}
return "我是testH,id = " + id;
}
/*限流返回处理*/
public String block(@PathVariable("id") Integer id, BlockException ex) {
return "服务启动失败,已进入熔断,id:" + id;
}
/*服务降级处理*/
public String testFallback(@PathVariable("id") Integer id, Throwable ex) {
return "程序异常:" + ex.getMessage();
}
}
注意这里的两个方法的异常参数是一定要传的,因为:
① 方法签名匹配的强制性要求
@SentinelResource 的 blockHandler 和 fallback 方法需要严格匹配原方法的参数列表, 并在末尾追加异常参数。 这是 Sentinel 框架的设计约束, 目的是: 明确区分处理逻辑的触发场景(是 Sentinel 规则拦截还是业务异常), 确保框架能正确路由调用到对应的处理方法。②实现动态处理逻辑
通过异常参数,可以基于不同的错误类型动态调整响应内容,
例如:根据流控规则类型返回不同的提示。 针对特定业务异常(如网络超时)执行重试逻辑。
记录详细的异常日志用于监控分析。
4、热点规则
注意:这里的 热点 并不是指的接口,而是 参数
何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。
比如:
商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制
代码演示
@RestController
public class testHotKeyController {
@GetMapping("/testHotKey")
@SentinelResource(value = "HotKey", blockHandler = "handler")
public String testHotKey(@RequestParam(value = "p1", required = false) String p1,
/*required:此参数是否必填*/
@RequestParam(value = "p2", required = false) String p2) {
return "------testHotKey";
}
public String handler(String p1, String p2, BlockException e) {
return "---------服务限流---------";
}
}
sentinel配置
测试(多次请求)
- http://localhost:8402/testHotKey?p1=asdf
- http://localhost:8402/testHotKey?p1=chyb
- http://localhost:8402/testHotKey?p2=ajsd
会发现只要有p1都会有限流的情况,但是当p1=chyb时明显就不会了,这是因为我们设置的阀值为500
5、授权规则
根据设定的依据
origin
参数来设置 黑名单和白名单
代码演示:
/*设置黑白名单的参数名*/
@Component
public class MyRequestOriginParser implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest httpServletRequest) {
return httpServletRequest.getParameter("serverName");
}
}
/*这里不太懂的可以先往下看,后面会有解释*/
/*业务类*/
@RestController
public class EmpowerController {
@GetMapping(value = "/empower")
public String requestSentinel() {
return "Sentinel授权规则";
}
}
配置sentinel,添加授权
测试
http://localhost:8402/empower?serverName=test
会直接熔断,这是因为 serverName=test为黑名单
RequestOriginParser部分源码分析
为什么实现RequestOriginParser接口并重写parseOrigin方法就可以对黑白名单的控制?
这里我们查看官网
中的解释:
由此可知ContextUtil.enter(resourceName, origin)
调用这个方法来进行黑白名单的控制的其中调用过程是:
调用过程:
(这里我是直接从准备调用ContextUtil.enter
前开始往上寻找到我们重写的方法MyRequestOriginParser.parseOrigin
)
我们直接看到AbstractSentinelInterceptor
这个拦截器,中的preHandler(请求前)方法中
//...
String origin = this.parseOrigin(request);
String contextName = this.getContextName(request);
ContextUtil.enter(contextName, origin);
//....
这里的
ContextUtil.enter(contextName, origin);
就是我们要找的怎么调用方信息,
这时我们直接向前面找origin,这里就到了String origin = this.parseOrigin(request);
我们在看到这个方法,
//....
origin = this.baseWebMvcConfig.getOriginParser().parseOrigin(request);
//....
return origin;
//....
这个时候我们就知道origin就是调用
RequestOriginParser
接口的parseOrigin()
方法,而我们实现它并对和这个方法进行重写也就相当于间接的对origin进行修改了
(这里大家可以按照这个步骤打debug,按照方法的调用顺序就很清楚了)
6、规则的持久化
前言
在上述的过程中大家应该已经发现了每当重启的时候都要重新进行配置Sentinel,这时就需要持久化配置,但是Sentinel并没有自带持久化功能,需要结合Nacos才可以完成,
所以在这里在从述一下,这里的Sentinel版本要1.8以上,且Spring Cloud Alibaba
、Spring Cloud
、Spring Boot
三者的关系一定不要有依赖冲突
这里可以直接参看官网:https://sca.aliyun.com/docs/2023/overview/version-explain/
代码基本配置
这里可以继续使用上面的代码,但是有部分配置需要进行修改:
- 检查依赖是否有:
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
- 修改配置文件
server:
port: 8402
spring:
application:
name: cloudAlibaba-sentinelTest-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
port: 8719 #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
dashboard: localhost:8080 #sentinel的地址
web-context-unify: false # controller层的方法对service层调用不认为是同一个根链路
datasource:
# 测试流控规则的持久化
ds1:
nacos:
server-addr: localhost:8848
data-id: ${spring.application.name}
group-id: DEFAULT_GROUP
# 数量类型
data-type: json
# 源码地址:com.alibaba.cloud.sentinel.datasource.RuleType
# 有五种类型(对呀Sentinel中的规则):
# FLOW(流控)、DEGRADE(熔断)、PARAM_FLOW(热点)、SYSTEM(系统保护)、AUTHORITY(授权)
rule-type: flow
# 测试熔断规则的持久化
ds2:
nacos:
server-addr: localhost:8848
data-id: ${spring.application.name}_degrade
group-id: DEFAULT_GROUP
data-type: json
rule-type: degrade
# 测试热点规则的持久化
ds3:
nacos:
server-addr: localhost:8848
data-id: ${spring.application.name}_param_flow
group-id: DEFAULT_GROUP
data-type: json
rule-type: param_flow
# 测试系统规则的持久化
ds4:
nacos:
server-addr: localhost:8848
data-id: ${spring.application.name}_system
group-id: DEFAULT_GROUP
data-type: json
rule-type: system
# 测试授权规则的持久化
ds5:
nacos:
server-addr: localhost:8848
data-id: ${spring.application.name}_authority
group-id: DEFAULT_GROUP
data-type: json
rule-type: authority
- 在nacos中创建配置持久化Sentinel规则
这里就不解释如何创建,直接开始配置,要是不知道的话可以看
《springCloud/Alibaba常用中间件之Nacos服务注册与发现》哪里又说
①:测试流控规则的持久化
创建完nacos配置之后,进行编辑:
配置规则及解释如下:(注意配置中要符合Json格式)
[
{
/*资源名*/
"resource": "/testB",
/*针对来源*/
"limitApp": "default",
/*限流阈值类型(1:QPS; 0:并发线程数)*/
"grade": 1,
/*单机阀值*/
"count": 1,
/*流控模式:0:直接; 1:关联; 2:链路*/
"strategy": 1,
/*流控效果:0:快速失败; 1:Warm Up(预热模式); 2:排队等待*/
"controlBehavior": 0,
/*关联资源、入口资源(关联、链路模式)*/
"refResource": "/testA",
/*是否打开集群*/
"clusterMode": false
/*
"strategy": 0, // 流控模式(0:直接; 1:关联; 2:链路)
"warmUpPeriodSec": 10, // 预热时间(秒,预热模式需要此参数)
*/
}
]
sentinel的web界面展示:
②:测试熔断规则的持久化
Nacos的配置:
[{
/*资源名*/
"resource": "/testF",
/*熔断策略,支持慢调用比例(0),异常比例(1),异常数(2)*/
"grade": 0,
/*统计时长(ms)*/
"statIntervalMs": 1000,
/*最小请求数*/
"minRequestAmount": 10,
/*熔断时长*/
"timeWindow": 10,
/*最大RT*/
"count": 1000,
/*比例阈值*/
"slowRatioThreshold": 0.1
}]
sentinel的web界面展示:
③:测试热点规则的持久化
Nacos配置:
[
{
/*资源名*/
"resource": "HotKey",
/*限流模式:QPS(1),可选项只有他,所以这里不设置也可以*/
"grade": 1,
/*参数索引*/
"paramIdx": 0,
/*单机阀值*/
"count": 1,
/*统计窗口时长*/
"durationInSec": 1,
/*是否开启集群*/
"clusterMode": false,
/*高级选项配置*/
"paramFlowItemList": [
{
/*参数类型(不写也可以,Nacos会自动判断)*/
"classType": "String",
/*参数值*/
"object": "chyb",
/*单机阀值*/
"count": 200
}
]
}
]
Setinel的web界面展示:
④:测试系统规则的持久化
Nacos配置:
[
{
"avgRt": -1, // RT
"highestCpuUsage": -1, // CPU 使用率
"highestSystemLoad": -1, // LOAD
"maxThread": 1, // 线程数
"qps": -1, // 入口 QPS
"count": 40, // 阈值,在CPU使用率中是百分比
}
]
Sentinel的web界面展示
⑥:测试授权规则的持久化
Nacos配置:
[
{
/*资源名*/
"resource": "/empower",
/*流控应用*/
"limitApp": "test1,test2",
/*授权类型:0(白名单),1(黑名单)*/
"strategy": 1
}
]
Setinel的web界面展示:
7、OpenFeign与Sentinel集成实现fallback服务降级
OpenFeign主要作用就是将微服务要暴漏给客户的API进行统一封装,从而方便管理。
而与Sentinel集成可以完成的一个核心的功能就是统一进行设置 fallback,这时就不需要每设计一个接口就要创建一个 *
fallback* 方法
代码实现演示:
准备代码:创建一个服务并提供一个接口用来测试,还要注册到nacos服务上,在创建一个Model并写Openfeign对外暴漏的API接口(可以前面的springCloud/Alibaba常用中间件——OpenFeign)
修改Openfeign接口,添加注解属性:fallback
/**
* value:服务端的服务名
* failback:指定服务降级后执行的类
*/
@FeignClient(value = "nacos-payment-provider", fallback = PayTwoFeignSentinelApiFallBack.class)
public interface PayFeignSentinelApiTwo {
// 对外暴漏的API接口
@GetMapping("/pay/nacos/get/{orderNo}")
ResultData getPayByOrderNo(@PathVariable("orderNo") String orderNo);
}
降级后执行的类代码演示
/*注入容器*/
@Component
/*实现接口,并重写方法作为此即可的服务降级处理*/
public class PayTwoFeignSentinelApiFallBack implements PayFeignSentinelApiTwo {
@Override
public ResultData getPayByOrderNo(String orderNo) {
return ResultData.fail(ReturnCodeEnum.RC201);
}
}
编写客户端
- pom依赖导入
<dependencies>
<!-- 引入自己定义的api通用包 -->
<dependency>
<groupId>com.chyb.cloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--alibaba-sentinel-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--nacos-discovery-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--loadbalancer-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<!--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>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
- 编写配置,并修改启动类
server:
port: 83
spring:
application:
name: nacos-sentinelFeign-order-consumer
cloud:
nacos:
discovery:
server-addr: localhost:8848
#消费者将要去访问的微服务名称(nacos微服务提供者叫什么你写什么)
service-url:
nacos-user-service: http://nacos-payment-provider
# 激活Sentinel对Feign的支持
feign:
sentinel:
enabled: true
@SpringBootApplication
@EnableDiscoveryClient/*启用服务发现*/
@EnableFeignClients/*启动openFeign*/
public class Main83 {
public static void main(String[] args) {
SpringApplication.run(Main83.class, args);
}
}
- 编写业务类
@RestController
public class testFeignSentinel {
@Resource
private PayFeignSentinelApiTwo payFeignSentinelApiTwo;
@GetMapping(value = "/consumer/pay/nacos/get/{orderNo}")
public ResultData getPayByOrderNo(@PathVariable("orderNo") String orderNo) {
return payFeignSentinelApiTwo.getPayByOrderNo(orderNo);
}
}
- 测试
启动服务和客户之后,查看暴漏的API接口(若是前面没有错误的话是正常的状态),
然后再将服务端直接关掉,在使用客户端进行请求便会直接到对应的服务降级处理方法哪里
8、GateWay与Sentinel集成实现集体服务限流
概念:GateWay网关是用来对外部请求进行过滤以及管理等操作,结合Sentinel可以更细致化的去控制请求。
注意:Openfeign和GateWay两个与Sentinel的集成别搞混了,如下图所示:
维度 | OpenFeign + Sentinel | Gateway + Sentinel |
---|---|---|
流量类型 | 服务间调用(东西流量) | 外部请求入口(南北流量) |
限流粒度 | 服务级别(如限制调用 user-service) | 全局入口级别(如限制 /api/** 路径) |
防护目标 | 保护调用方(防止下游服务故障拖垮自己) | 保护整个系统(防止外部流量压垮后端服务) |
参数级控制 | 不支持(需自定义代码) | 支持(如按 IP、Header 限流) |
若是还是一脸懵的话就记住:
Openfeign是控制服务之间的调用,解决了服务之间的依赖问题。
而GateWay是控制外部请求的调用,解决入口层的高并发和安全问题。
代码演示:
- pom依赖导入
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.8.6</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
<version>1.8.6</version>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
<scope>compile</scope>
</dependency>
<!--nacos-discovery-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--添加负载均衡的依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
- 修改yml和启动类
server:
port: 9530
spring:
application:
name: cloudalibaba-sentinel-gateway-test
cloud:
nacos:
discovery:
server-addr: localhost:8848
gateway:
routes:
- id: pay_routh
# uri: http://localhost:9001 服务网址
uri: lb://nacos-payment-provider #使用负载均衡和服务名进行动态访问
predicates:
- Path=/pay/** #配置Path的过滤
@SpringBootApplication
@EnableDiscoveryClient/*nacos服务注册*/
public class Main9530 {
public static void main(String[] args) {
SpringApplication.run(Main9530.class, args);
}
}
- 创建配置类
@Configuration
public class GatewayConfiguration {
/*这段代码是 Spring Cloud Gateway 集成 Sentinel 流量控制的核心配置,主要用于注册 Sentinel 的全局过滤器和自定义的异常处理器,实现网关层面的流量控制(如限流、熔断)及规则触发后的响应处理。
直接可以在在官网上复制下来:https://sentinelguard.io/zh-cn/docs/api-gateway-flow-control.html*/
/*----------作用:
流量拦截:通过全局过滤器检查 Sentinel 规则。
异常处理:自定义限流、熔断后的响应。
响应格式适配:支持 JSON、HTML 等多种格式。
-------------------*/
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider, ServerCodecConfigurer serverCodecConfigurer) {
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
// Register the block exception handler for Spring Cloud Gateway.
return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
}
@Bean
@Order(-1)
public GlobalFilter sentinelGatewayFilter() {
return new SentinelGatewayFilter();
}
/*--------------------------------------------------*/
/*标记一个方法在对象依赖注入完成后立即执行,*/
@PostConstruct //javax.annotation.PostConstruct
public void doInit() {
initBlockHandler();
}
//处理/自定义返回的例外信息。
private void initBlockHandler() {
Set<GatewayFlowRule> rules = new HashSet<>();
/*自定义流控规则*/
rules.add(new GatewayFlowRule("pay_routh1")
/*设置单机阀值*/
.setCount(2)
/*设置间隔时间*/
.setIntervalSec(1));
/*将自定义的流控规则,加载到Sentinel中*/
GatewayRuleManager.loadRules(rules);
BlockRequestHandler handler = new BlockRequestHandler() {
/**
* 触发限流后反会的信息
*
* @param exchange 请求的信息列如请求/响应报文等,这里在自定义网关哪里有说
* @param t 必须要带的异常参数,类似于fallback中的异常参数
* @return
*/
@Override
public Mono<ServerResponse> handleRequest(ServerWebExchange exchange, Throwable t) {
Map<String, String> map = new HashMap<>();
map.put("errorCode", HttpStatus.TOO_MANY_REQUESTS.getReasonPhrase());
map.put("errorMessage", "请求太过频繁,系统忙不过来,触发限流(sentinel+gataway整合Case)");
return ServerResponse
/*设置Http响应状态*/
.status(HttpStatus.TOO_MANY_REQUESTS)
/*指定响应内容类型*/
.contentType(MediaType.APPLICATION_JSON)
/*响应体,通过BodyInserters.fromValue将map转发为json*/
.body(BodyInserters.fromValue(map));
}
};
/*Sentinel的网关回调管理器,用于注册自定义处理器(如限流响应、异常处理等)*/
GatewayCallbackManager
/*注册到Sentinel,覆盖默认的限流响应行为*/
.setBlockHandler(handler);
}
}
GatewayFlowRule对象中的字段介绍:参考官方文档
resource
:资源名称,可以是网关中的 route 名称或者用户自定义的 API 分组名称。resourceMode
:规则是针对 API Gateway 的 route(RESOURCE_MODE_ROUTE_ID)还是用户在 Sentinel 中定义的 API 分组(RESOURCE_MODE_CUSTOM_API_NAME),默认是 route。grade
:限流指标维度,同限流规则的 grade 字段。count
:限流阈值intervalSec
:统计时间窗口,单位是秒,默认是 1 秒。controlBehavior
:流量整形的控制效果,同限流规则的 controlBehavior 字段,目前支持快速失败和匀速排队两种模式,默认是快速失败。burst
:应对突发请求时额外允许的请求数目。maxQueueingTimeoutMs
:匀速排队模式下的最长排队时间,单位是毫秒,仅在匀速排队模式下生效。paramItem
:参数限流配置。若不提供,则代表不针对参数进行限流,该网关规则将会被转换成普通流控规则;否则会转换成热点规则。其中的字段:parseStrategy
:从请求中提取参数的策略,目前支持提取来源 IP(PARAM_PARSE_STRATEGY_CLIENT_IP)、Host(PARAM_PARSE_STRATEGY_HOST)、任意 Header(PARAM_PARSE_STRATEGY_HEADER)和任意 URL 参数(PARAM_PARSE_STRATEGY_URL_PARAM)四种模式。fieldName
:若提取策略选择 Header 模式或 URL 参数模式,则需要指定对应的 header 名称或 URL 参数名称。pattern
:参数值的匹配模式,只有匹配该模式的请求属性值会纳入统计和流控;若为空则统计该请求属性的所有值。(1.6.2 版本开始支持)matchStrategy
:参数值的匹配策略,目前支持精确匹配(PARAM_MATCH_STRATEGY_EXACT)、子串匹配(PARAM_MATCH_STRATEGY_CONTAINS)和正则匹配(PARAM_MATCH_STRATEGY_REGEX)。(1.6.2 版本开始支持)
- 测试
直接通过网关端口进行范文服务API多次请求看是否会触发熔断规则,并降级。
上述大部分代码以上传到gitee:https://gitee.com/banhuayue/springCloud-Alibaba-code.git