目录
sentinel是用来做限流、隔离、降级、熔断的功能。本质要做的就是统计数据和规则判断
在微服务调用链路中的某个服务故障,引起整个链路中的所有微服务都不可用,称为雪崩

解决雪崩问题的常见方式有四种



Sentinel读 sēn tǐ nǒu,Hystrix读 hēi sǐ trǐ kě
| Sentinel | Hystrix | |
| 隔离策略 | 信号量隔离 | 线程池隔离/信号量隔离 |
| 熔断降级策略 | 基于慢调用比例或异常比例 | 基于失败比率 |
| 实时指标实现 | 滑动窗口 | 滑动窗口 (基于 RxJava) |
| 规则配置 | 支持多种数据源 | 支持多种数据源 |
| 扩展性 | 多个扩展点 | 插件的形式 |
| 基于注解的支持 | 支持 | 支持 |
| 限流 | 基于 QPS,支持基于调用关系的限流 | 有限的支持 |
| 流量整形 | 支持慢启动、匀速排队模式 | 不支持 |
| 系统自适应保护 | 支持 | 不支持 |
| 控制台 | 开箱即用,可配置规则、查看秒级监控、机器发现等 | 不完善 |
| 常见框架的适配 | Servlet、Spring Cloud、Dubbo、gRPC | Servlet、Spring Cloud Netflix |
Sentinel是阿里巴巴开源的一款微服务流量控制组件。官网地址:https://sentinelguard.io/zh-cn/index.html
Sentinel 具有以下特征:
sentinel官方提供了UI控制台,方便我们对系统做限流设置
sentinel-dashboard-1.8.1.jar 下载: https://cowtransfer.com/s/14e414d742ae4b
在D盘新建sentinel-dashboard目录,把下载的jar包粘贴进sentinel-dashboard目录,输入CMD如下
- d:
- cd sentinel-dashboard
- java -jar sentinel-dashboard-1.8.1.jar


localhost:8080

登录sentinel控制台

修改sentinel的默认端口、用户、密码
| 配置项 | 默认值 | 说明 |
| server.port | 8080 | 服务端口 |
| sentinel.dashboard.auth.username | sentinel | 默认用户名 |
| sentinel.dashboard.auth.password | sentinel | 默认密码 |
java -jar sentinel-dashboard-1.8.1.jar -Dserver.port=8090 #这条命令我这边运行是无效的,指定不了端口
java -jar sentinel-dashboard-1.8.1.jar --server.port=8090
提供了一个写好的cloud-demo微服务项目,下载后解压得到cloud-demo文件夹,里面有两个sql文件,导入进自己的数据库
https://cowtransfer.com/s/acdf30714d5741
cloud-demo项目结构如下图

第一步: 用idea打开cloud-demo微服务项目,修改application.yml的数据库连接信息

第二步: 本地启动nacos注册中心(默认是8848端口)。m表示启动模式,standalone表示单机启动。除了单机启动模式,还有集群启动的模式
第三步: 为避免端口冲突,关闭sentinel,重新启动sentinel(指定为8090端口)
- java -jar sentinel-dashboard-1.8.1.jar -Dserver.port=8090 #这条命令我这边运行是无效的,指定不了端口
- java -jar sentinel-dashboard-1.8.1.jar --server.port=8090
第四步: 先运行nacos注册中心运行cloud-demo微服务项目的UserApplication(8081端口)、OrderApplication(8088端口)、GatewayApplication(10010端口)引导类

第四步: 浏览器访问
http://localhost:8081/user/3

第五步: 在order-service中整合sentinel,并且连接sentinel的控制台。需要在order-service的pom.xml添加如下
- <!--整合sentinel-->
- <dependency>
- <groupId>com.alibaba.cloud</groupId>
- <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
- </dependency>
第六步: 在order-service中整合sentinel,并且连接sentinel的控制台。需要在order-service的application.yml添加如下
- spring:
- cloud:
- # 配置sentinel
- sentinel:
- transport:
- dashboard: localhost:8090 # 你启动sentinel控制台jar包的端口,默认是8080,但是我设置成了8090

第七步: 重新运行order-service的OrderApplication引导类
第八步: 浏览器访问(多访问几次,等下sentinel监控曲线会更明显)order-service微服务的任意端点(也就是任意地址),触发sentinel监控

第九步: 浏览器访问sentinel控制台,查看是否能监控到order-service微服务项目,也就是order-service有没有整合sentinel成功

如果你order-service被访问的少,或者没访问量,那么上图的 '实时监控' 曲线不显示,解决就是使劲访问你的order-service,例如访问下面那个地址
下面我们会详细学习如何使用sentinel的控制台,去管理我们的order-service项目
簇点链路:
就是项目内的调用链路,链路中被监控的每个接口就是一个资源。默认情况下sentinel会监控SpringMVC的每一个端点(Endpoint),因此SpringMVC的每一个端点(Endpoint)就是调用链路中的一个资源
流控、熔断等都是针对簇点链路中的资源来设置的,因此我们可以点击对应资源后面的按钮来设置规则,如下图


案例: 给 /order/{orderId}这个资源设置流控规则,QPS不能超过 5。然后利用jemeter测试
第一步: 浏览器访问sentinel控制台,并设置 '流控' 规则,也就是流量控制


第二步: 第一种测试方法。疯狂访问http://localhost:8088/order/101。需要1秒钟手点5次

第三步: 第二种测试方法。下一节来学
jmeter 读 jēi mī tě。 使用jmeter测试工具。jmeter下载如下
下载之后解压,在bin目录中找到 jmeter.properties,添加下面配置

然后打开里面bin目录的jmeter.bat文件,即可运行,运行期间不要关闭黑窗口,会弹出一个可视化页面来操作jemeter
为了方便,我们下载下面这个文件,下载到桌面,然后用jemeter打开这个文件



下载并配置好jmeter之后,紧接着上一节的测试



1、启动nacos(默认8848端口)。在命令行输入如下。m表示启动模式,standalone表示单机启动。除了单机启动模式,还有集群启动的模式
- d:
- cd D:\Nacos\nacos\bin
- startup.cmd -m standalone
2、启动sentinel(指定为8090端口)
- d:
- cd sentinel-dashboard
- java -jar sentinel-dashboard-1.8.1.jar --server.port=8090
3、运行cloud-demo微服务项目的UserApplication(8081端口)、OrderApplication(8088端口)、GatewayApplication(10010端口)引导类
4、浏览器访问(多访问几次,等下sentinel监控曲线会更明显)order-service微服务的任意端点(也就是任意地址),触发sentinel监控
5、sentinel监控。浏览器访问 http://localhost:8090
在添加限流规则时,点击高级选项,可以选择三种流控模式,分别是直接模式、关联模式、链路模式

演示其中的关联模式,需求如下
1、在OrderController新建两个端点:/order/query和/order/update,无需实现业务
2、配置流控规则,当/order/ update资源被访问的QPS超过5时,对/order/query请求限流
具体操作如下
第一步: 在order-service的OrderController添加如下
- @GetMapping("/query")
- public String queryOrder(){
- return "查询订单成功";
- }
-
- @GetMapping("/update")
- public String updateOrder(){
- return "更新订单成功";
- }
第二步: 重新运行OrderApplication引导类,然后浏览器访问 http://localhost:8088/order/query

第三步: 浏览器访问sentinel控制台 http://localhost:8090/

第四步: 添加流控规则,选择关联模式

第五步: 启动jmeter(读 jēi mī tě)。打开里面bin目录的jmeter.bat文件,即可运行,运行期间不要关闭黑窗口,会弹出一个可视化页面来操作jemeter


第六步: 查看jmeter的请求情况

第七步: 查看被关联的那个服务,也就是去访问一下 order/query,看有没有被限流

总结: 什么时候需要在限流规则里使用 '关联模式'
在添加限流规则时,点击高级选项,可以选择三种流控模式,分别是直接模式、关联模式、链路模式
●直接: 统计当前资源的请求,触发阈值时对当前资源直接限流,也是默认的模式 (我们在 '6. 限流规则' 演示的,默认就是直接模式)
●关联: 统计与当前资源相关的另一个资源,触发阈值时,对当前资源限流
○使用场景:比如用户支付时需要修改订单状态,同时用户要查询订单。查询和修改操作会争抢数据库锁,产生竞争。业务需求是有限支付和更新订单的业务,因此当修改订单业务触发阈值时,需要对查询订单业务限流
●链路: 统计从指定链路访问到本资源的请求,触发阈值时,对指定链路限流
○使用场景: 只针对从指定链路访问到本资源的请求做统计,判断是否超过阈值,例如有两条请求
链路: /test1 -> /common、/test2 -> /common。只希望统计从 /test2 进入到 /common 的请求
演示其中的链路模式,需求如下

需求: 有查询订单和创建订单业务,两者都需要查询商品。针对从查询订单进入到查询商品的请求统计,并设置限流
具体步骤如下
1、在OrderService中添加一个queryGoods方法,不用实现业务
2、在OrderController中,改造/order/query端点,调用OrderService中的queryGoods方法
3、在OrderController中添加一个/order/save的端点,调用OrderService的queryGoods方法
4、给queryGoods设置限流规则,从/order/query进入queryGoods的方法限制QPS必须小于2
具体操作如下
第一步: 在order-service的OrderService类添加如下
- @SentinelResource("goods")
- public void xxqueryGoods(){
- System.out.println("查询商品");
- }
第二步: 在order-service的application.yml修改一下
web-context-unify: false # 关闭context整合

第三步: 在order-service的的OrderController类的xxqueryOrder、xxupdateOrder方法修改为如如下
- @GetMapping("/query")
- public String xxqueryOrder(){
- //查询商品
- orderService.xxqueryGoods();
- System.out.println("查询订单");
- return "查询订单成功";
- }
-
- @GetMapping("/save")
- public String xxsaveOrder(){
- //查询商品
- orderService.xxqueryGoods();
- System.out.println("新增订单");
- return "新增订单成功";
- }
-
- @GetMapping("/update")
- public String xxupdateOrder(){
- return "更新订单成功";
- }
第四步: 重新运行OrderApplication引导类,然后浏览器访问 http://localhost:8088/order/query、save

第五步: 在浏览器的sentinel添加限流规则,模式为链路模式


第六步: 启动jmeter(读 jēi mī tě)。打开里面bin目录的jmeter.bat文件,即可运行,运行期间不要关闭黑窗口,会弹出一个可视化页面来操作jemeter



第七步: 查看jmeter的请求情况


流控效果是指请求达到流控阈值时应该采取的措施,包括三种

warm up也叫预热模式,是应对服务冷启动的一种方案。请求阈值初始值是 threshold / coldFactor,持续指定时长后,逐渐提高到threshold值。而coldFactor的默认值是3。例如,我设置QPS的threshold为10,预热时间为5秒,那么初始阈值就是 10 / 3 ,取整之后也就是3,然后在5秒后逐渐增长到10

需求: 给/order/{orderId}这个资源设置限流,最大QPS为10,利用warm up效果,预热时长为5秒。具体操作如下
第一步: 浏览器打开sentinel,在 /order/{orderId} 设置流控规则。
如果没有找到 /order/{orderId} ,就先疯狂访问http://localhost:8088/order/101,触发sentinel

第二步: 启动jmeter(读 jēi mī tě)。打开里面bin目录的jmeter.bat文件,即可运行,运行期间不要关闭黑窗口,会弹出一个可视化页面来操作jemeter


第三步: 查看jmeter的请求情况

当请求超过QPS阈值时,快速失败和warm up 会拒绝新的请求并抛出异常。而排队等待则是让所有请求进入一个队列中,然后按照阈值允许的时间间隔依次执行。后来的请求必须等待前面执行完成,如果请求预期的等待时间超出最大时长,则会被拒绝
例如:QPS = 5,意味着每200ms处理一个队列中的请求;timeout = 2000,意味着预期等待超过2000ms的请求会被拒绝并抛出异常

案例: 给/order/{orderId}这个资源设置限流,最大QPS为10,利用排队的流控效果,超时时长设置为5s。具体操作如下
第一步: 浏览器打开sentinel,在 /order/{orderId} 设置流控规则

第二步: 启动jmeter(读 jēi mī tě)。打开里面bin目录的jmeter.bat文件,即可运行,运行期间不要关闭黑窗口,会弹出一个可视化页面来操作jemeter


第三步: 查看jmeter的请求情况

之前的限流是统计访问某个资源的所有请求,判断是否超过QPS阈值。而热点参数限流是分别统计参数值相同的请求,判断是否超过QPS阈值


需求: 给/order/{orderId}这个资源添加热点参数限流,规则如下
1、默认的热点参数规则是每1秒请求量不超过2
2、给102这个参数设置例外:每1秒请求量不超过4
3、给103这个参数设置例外:每1秒请求量不超过10
具体操作如下
第一步: 由于热点 '参数限流' 对默认的SpringMVC资源无效,所以我们要先去order-service项目的OrderController类的queryOrderByUserId方法添加如下注解
@SentinelResource("hot")
第二步: 重新运行OrderApplication引导类,然后浏览器访问 http://localhost:8088/order/101,触发sentinel
第三步: 浏览器打开sentinel,在 /order/{orderId} 设置热点规则

第四步: 启动jmeter(读 jēi mī tě)。打开里面bin目录的jmeter.bat文件,即可运行,运行期间不要关闭黑窗口,会弹出一个可视化页面来操作jemeter




第五步: 查看jmeter的请求情况



总结: 热点参数限流是一种更细粒度的限流,可以精细到参数级别,如果有更细粒度限流的需求,就可以使用热点参数限流
- d:
- cd D:\Nacos\nacos\bin
- startup.cmd -m standalone
- d:
- cd sentinel-dashboard
- java -jar sentinel-dashboard-1.8.1.jar --server.port=8090
http://localhost:8088/order/101
- d:
- cd D:\apache-jmeter-5.4.1\bin
- jmeter.bat
虽然限流可以尽量避免因高并发而引起的服务故障,但服务还会因为其它原因而故障。而要将这些故障控制在一定范围,避免雪崩,就要靠线程隔离(舱壁模式)和熔断降级手段了
不管是线程隔离还是熔断降级,都是对客户端(调用方)的保护,避免坏的微服务拖垮
SpringCloud中,微服务调用都是通过Feign来实现的,因此做客户端保护必须整合Feign和Sentinel。整合的具体操作如下

第一步: 在order-service项目的application.yml添加如下,开启Feign的Sentinel功能
- feign:
- sentinel:
- enabled: true #开启Feign的sentinel功能

第二步: 在feign-api项目的clients目录新建fallback.UserClientFallbackFactory类,实现FallbackFactory工厂
- package cn.itcast.feign.clients.fallback;
-
- import cn.itcast.feign.clients.UserClient;
- import cn.itcast.feign.pojo.User;
- import feign.hystrix.FallbackFactory;
- import lombok.extern.slf4j.Slf4j;
-
-
- //实现FallbackFactory接口,泛型是我们关联的Feign客户端接口,也就是UserClient
- @Slf4j
- public class UserClientFallbackFactory implements FallbackFactory<UserClient> {
- @Override
- public UserClient create(Throwable throwable) {
- ///创建UserClient接口实现类,实现其中的方法,编写失败降级的处理逻辑
- return new UserClient() {
- @Override
- //在这个方法里面编写降级的逻辑,可以是返回友好的提示,也可以是返回默认结果
- public User findById(Long id) {
- log.error("查询用户异常",throwable);
- //返回空的用户对象
- return new User();
- }
- };
- }
- }
第三步: 把刚刚的UserClientFallbackFactory类注册为一个bean。在feign-api项目的DefaultFeignConfiguration类添加如下
- @Bean
- public UserClientFallbackFactory userClientFallbackFactory(){
- return new UserClientFallbackFactory();
- }
第四步: 在feign-api项目的UserClient接口的FeignClient注解添加如下
fallbackFactory = UserClientFallbackFactory.class

第五步: 重启order-service项目
第六步: 多访问几次 http://localhost:8088/order/101,触发sentinel
第七步: 浏览器访问sentinel页面 http://localhost:8090/

先把上面那节做完,再做这一节
线程隔离有两种方式实现

两种线程隔离方式的区别如下表。
扇出: 依赖的服务越多、扇出就越高、调用的就越多,线程要开启的就越多,消耗就越大。例如网关的扇出就很高

| 信号量隔离 | 线程池隔离 | |
| 优点 | 轻量级,无额外开销 | 支持主动超时、支持异步调用 |
| 缺点 | 不支持主动超时、异步调用 | 线程的额外开销比较大 |
| 场景 | 高频调用、高扇出的时候适合使用信号量隔离 | 低扇出的时候适合使用线程池隔离 |
Sentinel如何实现信号量隔离(是线程隔离的其中一种方式),相关概念如下
1、QPS:就是每秒的请求数,在快速入门中已经演示过
2、线程数:是该资源能使用用的tomcat线程数的最大值。也就是通过限制线程数量,实现舱壁模式

需求: 给UserClient的查询用户接口设置流控规则,线程数不能超过 2。然后利用jmeter测试。具体操作如下
第一步: 浏览器访问sentinel页面 http://localhost:8090/

第二步: 启动jmeter(读 jēi mī tě)。打开里面bin目录的jmeter.bat文件,即可运行,运行期间不要关闭黑窗口,会弹出一个可视化页面来操作jemeter


第三步: 查看jmeter的请求情况。虽然后面几个没报错,但是本质是报错的,只是被我们降级处理过,如可去idea看降级的处理代码

第四步: 由于在feign-api项目的UserClient接口添加了降级策略,所以当线程超出的时候,不会报错,而是会走UserClientFallbackFactory类写好的降级方法,也就是findById方法。如下图

熔断降级是解决雪崩问题的重要手段。其思路是由断路器(也叫状态机,包含下图的三个状态Closed、Open、Half-Open)统计服务调用的异常比例、慢请求比例,如果超出阈值则会熔断该服务。即拦截访问该服务的一切请求;而当服务恢复时,断路器会放行访问该服务的请求。Sentinel如何实现熔断降级

断路器熔断策略有三种:慢调用、异常比例、异常数
慢调用:业务的响应时长(RT)大于指定时长的请求认定为慢调用请求。在指定时间内,如果请求数量超过设定的最小数量,慢调用比例大于设定的阈值,则触发熔断。'调用' 也叫 '慢调用比例'

上图表示: RT超过500ms的调用是慢调用,统计最近10000ms内的请求,如果请求量超过10次,并且慢调用比例不低于0.5,则触发熔断,熔断时长为5秒。然后进入half-open状态,放行一次请求做测试
需求: 给 UserClient的查询用户接口设置降级规则,慢调用的RT阈值为50ms,统计时间为1秒,最小请求数量为5,失败阈值比例为0.4,熔断时长为5
具体操作如下
第一步: 为了触发慢调用规则,我们需要修改UserService中的业务,增加业务耗时。把user-service项目的UserController类的queryById方法修改为如下
- @GetMapping("/{id}")
- public User queryById(@PathVariable("id") Long id,
- @RequestHeader(value = "Truth", required = false) String truth) throws InterruptedException {
-
- if(id == 1){
- //休眠,触发熔断
- Thread.sleep(60);
- }
- return userService.queryById(id);
- }
第二步: 重新启动user-service的UserApplication引导类,访问UserService中id为1的数据,看一下是否是会慢60毫秒

第三步: 浏览器访问sentinel页面 http://localhost:8090/,设置降级规则

第四步: 测试。浏览器不断刷新http://localhost:8088/order/101

上面刚学的慢调用,总结就是只要你请求的数据出现慢返回的情况,sentinel就会熔断该请求对应的服务。下面要学的异常比例,也就是只要你请求的数据出现多次返回异常的情况,sentinel就会熔断该请求对应的服务。'异常数' 也叫 '异常比例'
异常比例或异常数:统计指定时间内的调用,如果调用次数超过指定请求数,并且出现异常的比例达到设定的比例阈值(或超过指定异常数),则触发熔断


上面两张图是同样的作用,也就是 '异常比例' 和 '异常数',其实只有一个地方的区别,一个是填小数(占总比例),另一个是填整数(填多少是多少)
上面两张图的作用是: 统计最近1000ms内的请求,如果请求量超过10次,异常次数超过4次,则触发熔断,熔断时长为5秒。然后进入half-open状态,放行一次请求做测试
需求: 给 UserClient的查询用户接口设置降级规则,统计时间为1秒,最小请求数量为5,失败阈值比例为0.4,熔断时长为5。具体操作如下
第一步: 为了触发异常统计,我们需要修改UserService中的业务,抛出异常。把user-service项目的UserController类的queryById方法修改为如下
- @GetMapping("/{id}")
- public User queryById(@PathVariable("id") Long id,
- @RequestHeader(value = "Truth", required = false) String truth) throws InterruptedException {
- if(id == 1){
- //休眠,触发熔断
- Thread.sleep(60);
- } else if(id == 2){
- //当查询UserService微服务id=2的数据时,就抛一次异常
- throw new RuntimeException("故意出错,作用是触发熔断");
- }
- return userService.queryById(id);
- }
第二步: 重新启动user-service的UserApplication引导类,访问UserService中id为2的数据,看一下是否是会报异常导致查不出数据

第三步: 浏览器访问sentinel页面 http://localhost:8090/,设置降级规则

第四步: 测试。浏览器不断刷新http://localhost:8088/order/102,访问5次以上


- d:
- cd D:\Nacos\nacos\bin
- startup.cmd -m standalone
- d:
- cd sentinel-dashboard
- java -jar sentinel-dashboard-1.8.1.jar --server.port=8090
http://localhost:8088/order/101
- d:
- cd D:\apache-jmeter-5.4.1\bin
- jmeter.bat
授权规则可以对调用方的来源做控制,有白名单和黑名单两种方式



案例: 给/order/{orderId} 配置授权规则。具体操作如下
第一步: 在order-service项目的cn.itcast.order目录新建sentinel.HeaderOriginParser类,写入如下
- package cn.itcast.order.sentinel;
-
- import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
- import org.apache.commons.lang.StringUtils;
- import org.springframework.stereotype.Component;
-
- import javax.servlet.http.HttpServletRequest;
-
-
- @Component
- //新建的这个类要去实现RequestOriginParser接口
- public class HeaderOriginParser implements RequestOriginParser {
- @Override
- public String parseOrigin(HttpServletRequest xxrequest) {
- //尝试获取请求头
- String y_origin = xxrequest.getHeader("yyorigin");
- //非空判断
- if(StringUtils.isEmpty(y_origin)){
- //如果请求头为空,就给一个默认的值,避免为空
- y_origin="blank";
- }
- //有请求头的话,就下一行return返回
- return y_origin;
- }
- }
第二步: 在gateway项目的application.yml添加如下,例如网关的过滤器给请求加一个请求头叫yyorigin,值是yyorigin_value
- AddRequestHeader=yyorigin,yyorigin_value #所有经过网关的请求都会带上yyorigin请求头,值是yyorigin_value

第三步: 重启GatewayApplication引导类、OrderApplication引导类
第四步: 浏览器访问sentinel页面 http://localhost:8090/,设置授权规则

第五步: 测试。访问 http://loalhost:8088/order/101,查看从浏览器直接访问是否被允许访问

第六步: 测试。访问 http://localhost:10010/order/101,查看从网关访问是否被允许访问
如果还是不行就访问 http://localhost:10010/order/101?authorization=admin

在前面所有不符合我们在sentinel指定的规则的请求,都会在页面报错,但是报错不雅观,而且不管是什么问题都是同一个报错页面在浏览器
下面我们将学习自定义异常,默认情况下,发生限流、降级、授权拦截时,都会抛出异常到调用方。如果要自定义异常时的返回结果,需要实现BlockExceptionHandler接口。
而BlockException包含很多个子类,分别对应不同的场景
| 异常 | 说明 |
| FlowException | 限流异常 |
| ParamFlowException | 热点参数限流的异常 |
| DegradeException | 降级异常 |
| AuthorityException | 授权规则异常 |
| SystemBlockException | 系统规则异常 |
具体操作如下
第一步: 在order-service项目的sentinel目录新建SentinelExceptionHandler类,写入如下
- package cn.itcast.order.sentinel;
-
- import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
- import com.alibaba.csp.sentinel.slots.block.BlockException;
- import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
- import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
- import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
- import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
- import org.springframework.stereotype.Component;
-
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
-
- @Component
- //在这个类实现BlockExceptionHandler接口
- public class SentinelExceptionHandler implements BlockExceptionHandler {
- @Override
- public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
- String msg = "未知异常";
- int status = 429;
-
- if (e instanceof FlowException) {
- msg = "请求被限流了";
- } else if (e instanceof ParamFlowException) {
- msg = "请求被热点参数限流";
- } else if (e instanceof DegradeException) {
- msg = "请求被降级了";
- } else if (e instanceof AuthorityException) {
- msg = "没有权限访问";
- status = 401;
- }
-
- response.setContentType("application/json;charset=utf-8");
- response.setStatus(status);
- response.getWriter().println("{\"msg\": " + msg + ", \"status\": " + status + "}");
- }
- }
第二步: 重新启动OrderApplication引导类
第三步: 浏览器访问sentinel页面 http://localhost:8090/,设置一些规则

第四步: 查看这次的错误页面长什么样


在前面学习的所有为sentinel配置规则时,只要是服务重启,那么规则就失效,需要重新配置一次,原因是sentinel默认会把这些规则保存在内存里,当重启的时候就丢失了。下面就来学如何让规则持久化的相关知识,分几节来学
Sentinel的控制台规则管理有三种模式
| 推送模式 | 说明 | 优点 | 缺点 |
| 原始模式 | API 将规则推送至客户端并直接更新到内存中,扩展写数据源,默认就是这种 | 简单,无任何依赖 | 不保证一致性;规则保存在内存中,重启即消失。严重不建议用于生产环境 |
| Pull 模式 | 扩展写数据源,客户端主动向某个规则管理中心定时轮询拉取规则,,这个规则中心可以是RDBMS文件 | 简单,无任何依赖;规则持久化 | 不保证一致性;实时性不保证,拉取过于频繁也可能会有性能问题 |
| Push 模式 | 扩展读数据源,规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 Nacos、Zookeeper 等配置中心。这种方式有更好的实时性和一致性保证。生产环境下一般采用 push 模式的数据源 | 规则持久化;一致性 | 引入第三方依赖 |
原始模式: 控制台配置的规则直接推送到Sentinel客户端,也就是我们的应用。然后保存在内存中,服务重启则丢失

pull模式: 控制台将配置的规则推送到Sentinel客户端,而客户端会将配置规则保存在本地文件或数据库中。以后会定时去本地文件或数据库中查询,更新本地规则

push模式: 控制台将配置规则推送到远程配置中心,例如Nacos。Sentinel客户端监听Nacos,获取配置变更的推送消息,完成本地配置更新

push模式实现最为复杂,依赖于nacos,并且需要改在Sentinel控制台。整体步骤如下:
具体操作如下
第一步: 在order-service的pom.xml添加如下,作用是引入sentinel监听nacos的依赖
- <dependency>
- <groupId>com.alibaba.csp</groupId>
- <artifactId>sentinel-datasource-nacos</artifactId>
- </dependency>
第二步: 在order-service中的application.yml修改相关配置为如下,作用是配置nacos地址及监听的配置信息
- spring:
- cloud:
- sentinel:
- datasource:
- flow:
- nacos:
- server-addr: localhost:8848 # nacos地址
- dataId: orderservice-flow-rules
- groupId: SENTINEL_GROUP
- rule-type: flow # 还可以是:degrade、authority、param-flow

第三步: 重新启动OrderApplication引导类
第四步: 下载sentinel-dashboard.jar包。下载到你的sentinel目录,例如我的是 'D:\sentinel-dashboard'
https://cowtransfer.com/s/26e336459c5247
第五步: 停止官方sentinel的运行,去运行上面你下载的这个sentinel。注意启动时Nacos要修改成你的Nacos地址,sentinel启动端口自定义为8090
- d:
- cd sentinel-dashboard
- java -jar sentinel-dashboard.jar --nacos.addr=localhost:8848 --server.port=8090
第六步: 浏览器访问sentinel页面 http://localhost:8090
如果进入什么都没有,就访问 http://localhost:8088/order/101,多访问几次触发sentinel,然后再回来访问就行了

第七步: 在sentinel添加一个流控规则(限流规则),注意必须在 '流控规则-NACOS' 加才行

第八步: 浏览器访问nacos页面

第九步: 测试。验证这个流控规则有没有生效。疯狂访问 http://localhost:8088/order/101,超出1秒1次就会限流,我们在第七步设置的QPS为1

第十步: 测试。重启order-service项目服务(重启OrderApplication),看一下流控规则还会不会生效

也就是我们通过实现push模式,实现了规则持久化