Sentinel
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。 Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
1.sentinel特性
Sentinel 具有以下特征:
-
丰富的应用场景: Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、实时熔断下游不可用应用等。
-
完备的实时监控: Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
-
广泛的开源生态: Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、RPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
2. Sentinel控制台的安装
Sentinel提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能。本节将详细记录何如通过Sentinel控制台控制Sentinel客户端的各种行为。Sentinel控制台的功能主要包括:流量控制、降级控制、热点配置、系统规则和授权规则等。
2.1 下载Sentinel-dashboard
我们先去看对应的版本,从之前的章节,我们对应的springboot版本为2.6.3版,alibaba的2021.0.1.0版,所以去查看版本依赖,应该下载1.8.3的版本.
下载地址: https://github.com/alibaba/Sentinel/releases/tag/1.8.3
2.2 运行Sentinel-dashboard
因为是一个jar包,所以我们直接执行命令
java -jar sentinel-dashboard-1.8.3.jar
发现就是一个springboot项目,我们访问 http://localhost:8080
其中,用户名:sentinel 密码: sentinel
输入账号密码,就可以登录进去了,发现没有数据,因为需要有客户端上线才行,我们往下学习
2.3参数配置
更多可用的启动参数配置:
java -D参数名=参数值 -jar xx.jar
java -jar xx.jar --参数名=参数值
-Dsentinel.dashboard.auth.username=sentinel用于指定控制台的登录用户名为 sentinel;
-Dsentinel.dashboard.auth.password=123456用于指定控制台的登录密码为 123456,如果省略这两个参数,默认用户和密码均为 sentinel;
-Dserver.servlet.session.timeout=7200用于指定 Spring Boot 服务端 session 的过期时间,如 7200 表示 7200 秒;60m 表示 60 分钟,默认为 30 分钟;
-Dserver.port=8888 --修改服务启动端口
-Dcsp.sentinel.dashboard.server=consoleIp:port 指定控制台地址和端口
例如:
java -Dserver.port=8888 -Dscp.sentinel.dashboard.server=localhost:8888 -jar sentinel.jar
3.sentinel的测试
sentinel的服务端已经搭建了,接下来创建项目,测试sentinel的流控,监控等功能。
3.1创建项目sentinel-client
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.8</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.powernode</groupId>
<artifactId>01-sentinel-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>sentinel-client</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud-alibaba.version>2021.0.1.0</spring-cloud-alibaba.version>
</properties>
<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-sentinel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3.2配置文件application.yml
server:
port: 8081
spring:
application:
name: sentinel-client
cloud:
sentinel:
transport: # sentinel的传输端口和控制面板地址
port: 8719
dashboard: 127.0.0.1:8080
spring.cloud.sentinel.transport.dashboard 指定了sentinel控制台的ip和端口地址;
spring.cloud.sentinel.transport.port代表sentinel客户端和控制台通信的端口,默认为8719,如果这个端口已经被占用,那么sentinel会自动从8719开始依次+1扫描,直到找到未被占用的端口。
启动时加入 JVM 参数 -Dcsp.sentinel.dashboard.server=consoleIp:port 指定控制台地址和端口。若启动多个应用,则需要通过 -Dcsp.sentinel.api.port=xxxx 指定客户端监控 API 的端口(默认是 8719)。
3.3创建控制器功能
@RestController
public class TestController {
/**
* 测试的接口
*
* @return
*/
@GetMapping("hello")
public String hello() {
return "hello Sentinel";
}
}
3.4启动访问
输入 http://localhost:8081/hello 后查看sentinel-dashboard
控制台已经显示正常了。在簇点链路中可以看到刚刚那次请求,我们可以对它进行流控、降级、授权、热点等配置(控制台是懒加载的,如果没有任何请求,那么控制台也不会有任何内容)
4.流控规则
先在簇点链路中找到/hello接口,选择流控
-
资源名:标识资源的唯一名称,默认为请求路径,也可以在客户端中使用@SentinelResource配置;
-
针对来源:Sentinel可以针对服务调用者进行限流,填写微服务名称即spring.application.name,默认为default,不区分来源;
-
阈值类型、单机阈值:
QPS(Queries-per-second,每秒钟的请求数量):当调用该api的QPS达到阈值的时候,进行限流;
线程数:当调用该api的线程数达到阈值的时候,进行限流。
是否集群:默认不集群;
流控模式:
直接:当api调用达到限流条件的时,直接限流;
关联:当关联的资源请求达到阈值的时候,限流自己;
链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,则进行限流)。
- 流控效果:
快速失败:直接失败;
Warm Up:根据codeFactor(冷加载因子,默认值为3)的值,从阈值/codeFactor,经过预热时长,才达到设置的QPS阈值;
排队等待:匀速排队,让请求匀速通过,阈值类型必须设置为QPS,否则无效。
4.1QPS快速失败
4.1.1 添加流控规则
规则:QPS
单机阈值:2
流控模式:直接
流控效果: 快速失败
设置的效果是,1秒钟内请求/hello资源的次数达到2次以上的时候,进行限流。
4.1.2测试效果
现在我们快速访问 http://localhost:8081/hello
当手速快点的时候(1秒超过2次),页面返回Blocked by Sentinel (flow limiting)。并且响应码为429
4.1.3修改访问结果
默认返回是错误代码429,可以通过实现BlockExceptionHandler接口重写访问结果。
@Component
public class ServiceBlockExceptionHandler implements BlockExceptionHandler {
/*处理BlockException类型以及子类类型的异常
*
* */
@Override
public void handle(HttpServletRequest request,
HttpServletResponse response,
BlockException e) throws Exception {
// 设置响应数据编码
response.setCharacterEncoding("utf-8");
// 告诉客户端响应数据的类型,以及客户端显示内容的编码
response.setContentType("text/html;charset=utf-8");
Map<String,Object> map=new HashMap<>();
map.put("status", 429);
map.put("message","访问太频繁了");
String jsonStr=new ObjectMapper().writeValueAsString(map);
PrintWriter out = response.getWriter();
out.print(jsonStr);
out.flush();
out.close();
}
}
4.2 线程数快速失败
4.2.1修改Controller,模拟执行时长
我们模拟线程阻塞的情况,让线程不能及时回收,然后第二个请求线程进进来的时候就看出效果
/**
* 测试的接口
*
* @return
*/
@GetMapping("hello")
public String hello() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "hello Sentinel";
}
4.2.2 重启项目
修改controller以后重启项目,然后再添加流控规则,因为现在的所有规则都是临时的,然后重新访问一次/hello.
4.2.3添加流控规则
线程数:2 , 单机阈值:2 ,直接
这个配置效果是,当1s中有两个线程正在访问此接口,那么就会限流。测试快速访问,则抛出429
4.3 Warm Up 预热
流控效果除了直接失败外,我们也可以选择预热Warm Up。
Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过”冷启动”,让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。
sentinel客户端的默认冷加载因子coldFactor为3(源码写死了),即请求QPS从 threshold / 3 开始,经预热时长逐渐升至设定的QPS阈值。
4.3.1修改Controller
新增接口hello2
@GetMapping("hello2")
public String hello2() {
return "hello Sentinel2";
}
4.3.2 重启测试访问后添加流控规则
资源:hello2
阈值:QPS, 单机阈值: 10, 流控模式:直接,流控效果:Warm Up 预热时长: 5
此流控效果为,前5s访问速度每秒超过3次就限流, 5s以后访问速度每秒超过10次(我们配置的)就限流
前期在预热环境,突然的高QPS 会导致系统直接拒绝访问,慢慢地,开始大量的接受新的请求。
4.4 排队等待
先删除上面的流控规则,然后重新添加流控规则
排队等待方式不会拒绝请求,而是严格控制请求通过的间隔时间,也就是让请求以均匀的速度通过
4.4.1修改controller
/**
* 新增测试接口3
*
* @return
*/
@GetMapping("hello3")
public String hello3() {
System.out.println(LocalDateTime.now().toLocalTime());
return "hello Sentinel3";
}
4.4.2 重启后添加流控规则
资源:hello3
阈值:QPS,
单机阈值: 1
流控模式:直接
流控效果:排队等待
超时时间:2000
上述配置的含义是,访问/hello3请求每秒钟最多只能1次,超过的请求排队等待,等待超过2000毫秒则超时
4.4.3测试
查看控制台,每秒只有一个请求能进来
4.5关联
访问某个接口达到一定的流控规则后,开始限制本接口。关联中我们测试一下快速失败
4.5.1新增controller
我们新增两个controller,用于测试关联
/**
* 测试关联的A接口
*
* @return
*/
@GetMapping("testA")
public String testA() {
return "testA";
}
/**
* 测试关联的B接口
*
* @return
*/
@GetMapping("testB")
public String testB() {
return "testB";
}
4.5.2 重启后添加流控规则
资源:/testA
阈值:QPS,
单机阈值: 3
流控模式:关联
关联资源:/testB
流控效果:快速失败
上述配置的含义是,访问/testB接口请求每秒钟超过3次,那么限流/testA接口
4.5.3测试访问
快速访问/testB接口 然后尽快访问/testA,发现/testA已经限流了
4.6链路
程序的调用可以看成为一条链路。当触发链路的某条规则后,该链路被限流。
上图从API 出发,可以发现有2 条链路,分别为:
Link1–>hello–>other
Link2–>hello–>other
2 条链路在调用上,限流规则互补影响。
4.6.1 新增一个service和实现类
@Service
public class HelloServiceImpl implements HelloService{
/**
* 我们使用@SentinelResource(value = "hello")标记为此方法为一个资源
*
* @return
*/
@SentinelResource(value = "hello",blockHandler = "blockMethod")
public String hello() {
return "hello";
}
public String blockMethod(BlockException e) {
System.out.println(e.getMessage());
return "访问太快啦";
}
}
4.6.2修改controller
@Autowired
private HelloServiceImpl helloService;
/**
* 新增link1接口
*/
@GetMapping("link1")
public String link1() {
String hello = helloService.hello();
return "我是link1调用hello的结果" + hello;
}
/**
* 新增link2接口
*/
@GetMapping("link2")
public String link2() {
String hello = helloService.hello();
return "我是link2调用hello的结果" + hello;
}
4.6.3修改配置文件
server:
port: 8081
spring:
application:
name: sentinel-client
cloud:
sentinel:
transport:
port: 8719
dashboard: 127.0.0.1:8080
web-context-unify: false # 关闭context整合
4.6.4重启访问
http://localhost:8081/link1
http://localhost:8081/link2
4.6.5添加流控规则
资源:hello
阈值:QPS,
单机阈值: 2
流控模式:链路
入口资源:/link1
流控效果:快速失败
在入口资源,我们使用的是/link1,点击新增,完成对规则的添加。
上述配置的意思是,当通过/link1访问hello的时候,QPS大于2则进行限流;
言外之意就是/link2访问hello请求并不受影响。
5. 熔断规则
Sentinel除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。由于调用关系的复杂性,如果调用链路中的某个资源不稳定,最终会导致请求发生堆积。Sentinel 熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。当资源被降级后,在接下来的熔断时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出 DegradeException)。
当访问系统失败超过一定的次数后,对该接口进行熔断的操作。
我们可以发现,降级策略分为3种:
**RT/**慢调用比例,平均响应时间 (DEGRADE_GRADE_RT):当 1s 内持续进入 5 个请求,对应时刻的平均响应时间(秒级)均超过阈值(count,以 ms 为单位),那么在接下的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)之内,对这个方法的调用都会自动地熔断(抛出 DegradeException)。注意 Sentinel 默认统计的 RT 上限是 4900 ms,超出此阈值的都会算作 4900 ms,若需要变更此上限可以通过启动配置项 -Dcsp.sentinel.statistic.max.rt=xxx 来配置。
异常比例 (DEGRADE_GRADE_EXCEPTION_RATIO):当资源的每秒请求量 >= 5,并且每秒异常总数占通过量的比值超过阈值(DegradeRule 中的 count)之后,资源进入降级状态,即在接下的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
异常数 (DEGRADE_GRADE_EXCEPTION_COUNT):当资源近 1 分钟的异常数目超过阈值之后会进行熔断。注意由于统计时间窗口是分钟级别的,若 timeWindow 小于 60s,则结束熔断状态后仍可能再进入熔断状态。
5.1RT
当 1s 内持续进入 5 个请求,对应时刻的平均响应时间(秒级)均超过阈值(count,以 ms 为单位),那么在接下的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)之内,对这个方法的调用都会自动地熔断(抛出 DegradeException)
5.1.1 新增一个controller
/**
* testRt接口
*
* @return
*/
@GetMapping("testRt")
public String testRt() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "测试RT";
}
5.1.2 增加降级规则
先重启动项目,然后访问一次后,再新增降级规则
资源名: /testRt
熔断策略:慢调用比例
最大RT: 500
阈值: 1
熔断时长: 2
最小请求数:5
统计时长:5000
上述配置的含义是,访问/testRt 如果1s内五次请求的响应时间都超过500ms,就限流5s
-
如果有一个请求响应时间超过设置的rt(500ms)
-
那么就会判断接下来的一个时间窗口(5s)内,前5个请求的平均响应时间是否超过rt
-
如果超过了,进行预熔断,再次判断下个时间窗口内的前5个请求是否超过平均响应时间
-
如果超过了,接下来的请求会被熔断
-
经过熔断时长(2s,时间窗口的值)后,进入探测恢复状态(HALF-OPEN)阶段,即接下来的一个请求响应时间小于rt,则熔断结束,否则会再次被熔断
5.1.3测试访问
访问 http://localhost:8081/testRt 快速访问5次,后面就的就限流了,过2s后又可以继续访问了
5.2 异常比例
当资源的每秒请求量 >= 5,并且每秒异常总数占通过量的比值超过阈值之后,资源进入熔断状态,在接下来的时间窗口内,程序都会快速失败。
5.2.1 新增一个controller
/**
* testEx接口
*
* @return
*/
@GetMapping("testEx")
public String testEx() {
int count= new Random().nextInt(100);
if(count%2==0)
throw new RuntimeException("就是不想成功");
return "奇数:"+count;
}
5.2.2 增加降级规则
先重新项目,然后访问一次后,再新增熔断规则
资源名: /testEx
熔断策略:异常比例
比例阈值: 0.5
熔断时长: 3
最小请求数:5
统计时长:3000
上面的配置含义是:如果/testEx的QPS大于5,并且每秒钟的请求异常比例大于50%的话,那么在未来的3秒钟(时间窗口)内,sentinel断路器打开,该api接口不可用。
也就是说,如果一秒内有10个请求进来,超过5个以上都出错,那么会触发熔断,3秒钟内这个接口不可用。
5.2.3测试访问
多次快速请求后出现限流,5s窗口期过了以后,又可以访问了
5.3 异常数量
当指定时间窗口内,请求异常数大于等于某个值时,触发熔断。继续使用上面的接口测试。
删除之前的规则,新增规则
5.3.1 增加降级规则
资源名: /testEx
熔断策略:异常数
异常数: 5
熔断时长: 3
最小请求数:5
统计时长:10000
上述配置的含义是,访问/testEx 如果10s内访问接口出现异常超过5次,就熔断
5.3.2 测试访问
在10s内访问第6次就出现了限流
6 系统规则
系统规则则是针对整个系统设置限流规则,并不针对某个资源,设置页面如下:
阈值类型包含以下五种:
- Load 自适应(仅对 Linux/Unix-like 机器生效):系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的 maxQps minRt 估算得出。设定参考值一般是 CPU cores 2.5。
- 平均 RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
- 并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
- 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。
- CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。
7.Sentinel集成openfeign【重点】
我们使用nacos做注册中心,openfeign做远程调用,sentinel做限流熔断,和hystrix一样,只需要在配置文件修改开启feign对sentinel的支持即可
7.1创建提供者sentinel-provider
7.1.1pom文件
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.8</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.powernode</groupId>
<artifactId>02-sentinel-provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>sentinel-provider</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud-alibaba.version>2021.0.1.0</spring-cloud-alibaba.version>
</properties>
<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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
7.1.2配置文件application.yml
server:
port: 8001
spring:
application:
name: sentinel-provider
cloud:
nacos:
server-addr: localhost:8848
7.1.3修改启动类
@SpringBootApplication
@EnableDiscoveryClient
public class SentinelProviderApplication {
public static void main(String[] args) {
SpringApplication.run(SentinelProviderApplication.class, args);
}
}
7.1.4 创建一个controller
@RestController
public class ProviderController {
@GetMapping("provider")
public String provider(String name) {
return "我是提供者" + name;
}
}
7.1.5启动项目
7.2修改sentinel-client项目
7.2.1 修改pom.xml
完整的pom.xml如下
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.8</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.powernode</groupId>
<artifactId>01-sentinel-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>sentinel-client</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>2021.0.1</spring-cloud.version>
<spring-cloud-alibaba.version>2021.0.1.0</spring-cloud-alibaba.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<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>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
7.2.2 修改配置文件
server:
port: 8081
spring:
application:
name: sentinel-client
cloud:
sentinel:
transport: # sentinel的传输端口和控制面板地址
port: 8719
dashboard: 127.0.0.1:8080
nacos:
server-addr: localhost:8848
feign:
sentinel:
enabled: true # 开启feign对sentinel的支持
7.2.3修改启动类,开启feign
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class SentinelClientApplication {
public static void main(String[] args) {
SpringApplication.run(SentinelClientApplication.class, args);
}
}
7.2.4添加feign接口
@FeignClient(value = "sentinel-provider", fallback = ProviderFeignSentinel.class)
public interface ProviderFeign {
@GetMapping("provider")
String provider(@RequestParam("name") String name);
}
7.2.5添加feign熔断
@Component
public class ProviderFeignSentinel implements ProviderFeign {
@Override
public String provider(String name) {
return "我走了sentinel的熔断方法";
}
}
7.2.6 修改controller
@Autowired
private ProviderFeign providerFeign;
@GetMapping("testRpc")
public String testRpc(String name) {
String provider = providerFeign.provider(name);
return provider;
}
7.2.7启动测试
http://localhost:8081/testRpc?name=bjpowernode
至此sentinel集成openfeign完成,如果远程服务不可用,则启用熔断方法
8.Sentinel整合gateway完成限流
在gateway中使用了redis来完成限流,sentinel在1.6.0以后也主动支持了gateway完成限流功能,使用起来很方便.
8.1新建一个gateway服务,并且注册到nacos
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.powernode</groupId>
<artifactId>04-gateway</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>gateway</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.6.8</spring-boot.version>
<spring-cloud-alibaba.version>2021.0.1.0</spring-cloud-alibaba.version>
<spring-cloud.version>2021.0.1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-datasource</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</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>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
8.2 修改application.yml配置文件
server:
port: 80
spring:
application:
name: gateway
cloud:
gateway:
enabled: true
discovery:
locator: # 开启动态路由,可以通过服务名称做发现从而路由
enabled: true
lower-case-service-id: true
routes: # 写一个测试路由
- id: test-id
uri: lb://sentinel-provider
predicates:
- Path=/provider/**
nacos:
username: nacos
password: nacos
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080
port: 8719
scg: # 限流后的处理
fallback:
## 两种模式,一种是response返回文字提示信息,
## 一种是redirect,重定向跳转,需要同时配置redirect(跳转的uri)
mode: response
response-status: 200
response-body: '{"code": 429,"msg": "limited"}'
content-type: application/json
8.3 限流模式
实现限流机制主要由GatewayFlowRule与ApiDefinition两个核心类实现配置:
-
GatewayFlowRule(Route ID): 网关限流规则,针对 API Gateway 的场景定制的限流规则,可以针对不同 route 或自定义的 API 分组进行限流,支持针对请求中的参数、Header、来源 IP 等进行定制化的限流。
-
ApiDefinition(Api分组): 用户自定义的 API 定义分组,可以看做是一些 URL 匹配的组合。比如我们可以定义一个 API 叫 my_api,请求 path 模式为 /foo/** 和 /baz/** 的都归到 my_api 这个 API 分组下面。限流的时候可以针对这个自定义的 API 分组维度进行限流。
8.3.1 Route-id模式
然后快速访问 http://localhost/provider 后出现限流
8.3.2 Api分组模式
1 .新增api分组
- 添加流控规则
3.测试
快速访问 http://localhost/sentinel-provider/provider,出现限流
8.4持久化限流配置
我们在控制台添加的限流配置是临时的,在实际生产环境中可以使用nacos来做限流配置的持久化方案,我们可以将限流配置写在nacos的配置文件管理中。
提示信息,
## 一种是redirect,重定向跳转,需要同时配置redirect(跳转的uri)
mode: response
response-status: 200
response-body: ‘{“code”: 429,“msg”: “limited”}’
content-type: application/json