目录
Sentinel流量控制
1. 雪崩问题
2. 服务保护技术对比
3. 认识Sentinel
4. 安装启动Sentinel
sentinel-toc" style="margin-left:40px;">5. 微服务整合sentinel
6. 限流规则-直接模式
7. jmeter测试工具
8. 限流规则-关联模式
9. 限流规则-链路模式
10. 流控效果-预热模式
11. 流控效果-排队等待
12. 热点参数限流
sentinel%E9%9A%94%E7%A6%BB%E5%92%8C%E9%99%8D%E7%BA%A7-toc" style="margin-left:0px;">高级篇-sentinel隔离和降级
1. Feign整合Sentinel
2. 线程隔离
3. 熔断降级
4. 熔断降级-慢调用
5. 熔断降级-异常比例或异常数
sentinel%E6%8E%88%E6%9D%83%E8%A7%84%E5%88%99-toc" style="margin-left:0px;">高级篇-sentinel授权规则
1. 授权规则
2. 自定义异常结果
3. 规则持久化
3.1. 规则管理模式
3.2. 实现push模式
Sentinel流量控制
sentinel是用来做限流、隔离、降级、熔断的功能。本质要做的就是统计数据和规则判断
1. 雪崩问题
在微服务调用链路中的某个服务故障,引起整个链路中的所有微服务都不可用,称为雪崩
解决雪崩问题的常见方式有四种
- 1、超时处理: 设定超时时间,请求超过时间没有响应就返回错误信息,不会无休止等待。新的超时连接数/s 大于 释放的超时连接数/s 时,还是会雪崩
- 2、舱壁模式: 限定每个业务能使用的线程数,避免耗尽整个tomcat的资源,因此也叫线程隔离。完全解决雪崩,但是资源利用不好
- 3、熔断降级: 由熔断器统计业务执行的异常比例,如果超出阈值则会熔断该业务,拦截访问该业务的一切请求。完全解决雪崩
- 4、流量控制: 限制业务访问的QPS(每秒钟处理的请求数量),避免服务因流量的突增而故障。根源解决雪崩,使用的是Sentinel
2. 服务保护技术对比
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 |
3. 认识Sentinel
Sentinel是阿里巴巴开源的一款微服务流量控制组件。官网地址:https://sentinelguard.io/zh-cn/index.html
Sentinel 具有以下特征:
- ●丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等
- ●完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况
- ●广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel
- ●完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等
4. 安装启动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.dashboard.auth.password | 默认密码 |
java -jar sentinel-dashboard-1.8.1.jar -Dserver.port=8090 #这条命令我这边运行是无效的,指定不了端口
java -jar sentinel-dashboard-1.8.1.jar --server.port=8090
sentinel" style="background-color:transparent;">5. 微服务整合sentinel
提供了一个写好的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:# 配置sentinelsentinel: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项目
6. 限流规则-直接模式
簇点链路:
就是项目内的调用链路,链路中被监控的每个接口就是一个资源。默认情况下sentinel会监控SpringMVC的每一个端点(Endpoint),因此SpringMVC的每一个端点(Endpoint)就是调用链路中的一个资源
流控、熔断等都是针对簇点链路中的资源来设置的,因此我们可以点击对应资源后面的按钮来设置规则,如下图
案例: 给 /order/{orderId}这个资源设置流控规则,QPS不能超过 5。然后利用jemeter测试
第一步: 浏览器访问sentinel控制台,并设置 '流控' 规则,也就是流量控制
第二步: 第一种测试方法。疯狂访问http://localhost:8088/order/101。需要1秒钟手点5次
第三步: 第二种测试方法。下一节来学
7. jmeter测试工具
jmeter 读 jēi mī tě。 使用jmeter测试工具。jmeter下载如下
下载之后解压,在bin目录中找到 jmeter.properties,添加下面配置
然后打开里面bin目录的jmeter.bat文件,即可运行,运行期间不要关闭黑窗口,会弹出一个可视化页面来操作jemeter
为了方便,我们下载下面这个文件,下载到桌面,然后用jemeter打开这个文件
下载并配置好jmeter之后,紧接着上一节的测试
8. 限流规则-关联模式
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
在添加限流规则时,点击高级选项,可以选择三种流控模式,分别是直接模式、关联模式、链路模式
- ●直接: 统计当前资源的请求,触发阈值时对当前资源直接限流,也是默认的模式 (我们在 '6. 限流规则' 演示的,默认就是直接模式)
- ●关联: 统计与当前资源相关的另一个资源,触发阈值时,对当前资源限流 ○使用场景:比如用户支付时需要修改订单状态,同时用户要查询订单。查询和修改操作会争抢数据库锁,产生竞争。业务需求是有限支付和更新订单的业务,因此当修改订单业务触发阈值时,需要对查询订单业务限流
- ●链路: 统计从指定链路访问到本资源的请求,触发阈值时,对指定链路限流 ○使用场景: 只针对从指定链路访问到本资源的请求做统计,判断是否超过阈值
演示其中的关联模式,需求如下
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,看有没有被限流
总结: 什么时候需要在限流规则里使用 '关联模式'
- 1、两个有竞争关系的资源
- 2、一个优先级高,另一个优先级低,当优先级高的被大量访问时,对限流优先级低的那个做限流
9. 限流规则-链路模式
在添加限流规则时,点击高级选项,可以选择三种流控模式,分别是直接模式、关联模式、链路模式
●直接: 统计当前资源的请求,触发阈值时对当前资源直接限流,也是默认的模式 (我们在 '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的请求情况
10. 流控效果-预热模式
流控效果是指请求达到流控阈值时应该采取的措施,包括三种
- ●快速失败:达到阈值后,新的请求会被立即拒绝并抛出FlowException异常。是默认的处理方式。默认是这种
- ●warm up:预热模式,对超出阈值的请求同样是拒绝并抛出异常。但这种模式阈值会动态变化,从一个较小值逐渐增加到最大阈值
- ●排队等待:让所有的请求按照先后次序排队执行,两个请求的间隔不能小于指定时长
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的请求情况
11. 流控效果-排队等待
当请求超过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的请求情况
12. 热点参数限流
之前的限流是统计访问某个资源的所有请求,判断是否超过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的请求情况
总结: 热点参数限流是一种更细粒度的限流,可以精细到参数级别,如果有更细粒度限流的需求,就可以使用热点参数限流
sentinel%E9%9A%94%E7%A6%BB%E5%92%8C%E9%99%8D%E7%BA%A7" style="background-color:transparent;">
高级篇-sentinel隔离和降级
- 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监控
http://localhost:8088/order/101
- 5、sentinel监控。浏览器访问 http://localhost:8090
- 6、启动jemeter
d:
cd D:\apache-jmeter-5.4.1\bin
jmeter.bat
1. Feign整合Sentinel
虽然限流可以尽量避免因高并发而引起的服务故障,但服务还会因为其它原因而故障。而要将这些故障控制在一定范围,避免雪崩,就要靠线程隔离(舱壁模式)和熔断降级手段了
不管是线程隔离还是熔断降级,都是对客户端(调用方)的保护,避免坏的微服务拖垮
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> {@Overridepublic 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/
2. 线程隔离
先把上面那节做完,再做这一节
线程隔离有两种方式实现
- 线程池隔离
- 信号量隔离(Sentinel默认采用)
两种线程隔离方式的区别如下表。
扇出: 依赖的服务越多、扇出就越高、调用的就越多,线程要开启的就越多,消耗就越大。例如网关的扇出就很高
信号量隔离 | 线程池隔离 | |
优点 | 轻量级,无额外开销 | 支持主动超时、支持异步调用 |
缺点 | 不支持主动超时、异步调用 | 线程的额外开销比较大 |
场景 | 高频调用、高扇出的时候适合使用信号量隔离 | 低扇出的时候适合使用线程池隔离 |
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方法。如下图
3. 熔断降级
熔断降级是解决雪崩问题的重要手段。其思路是由断路器(也叫状态机,包含下图的三个状态Closed、Open、Half-Open)统计服务调用的异常比例、慢请求比例,如果超出阈值则会熔断该服务。即拦截访问该服务的一切请求;而当服务恢复时,断路器会放行访问该服务的请求。Sentinel如何实现熔断降级
断路器熔断策略有三种:慢调用、异常比例、异常数
4. 熔断降级-慢调用
慢调用:业务的响应时长(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
5. 熔断降级-异常比例或异常数
上面刚学的慢调用,总结就是只要你请求的数据出现慢返回的情况,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次以上
sentinel%E6%8E%88%E6%9D%83%E8%A7%84%E5%88%99" style="background-color:transparent;">
高级篇-sentinel授权规则
- 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监控
http://localhost:8088/order/101
- 5、sentinel监控。浏览器访问 http://localhost:8090
- 6、启动jemeter
d:
cd D:\apache-jmeter-5.4.1\bin
jmeter.bat
1. 授权规则
授权规则可以对调用方的来源做控制,有白名单和黑名单两种方式
- 白名单:来源 (origin) 在白名单内的调用者允许访问
- 黑名单:来源 (origin) 在黑名单内的调用者不允许访问
案例: 给/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 {@Overridepublic 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
2. 自定义异常结果
在前面所有不符合我们在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 {@Overridepublic 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/,设置一些规则
第四步: 查看这次的错误页面长什么样
3. 规则持久化
在前面学习的所有为sentinel配置规则时,只要是服务重启,那么规则就失效,需要重新配置一次,原因是sentinel默认会把这些规则保存在内存里,当重启的时候就丢失了。下面就来学如何让规则持久化的相关知识,分几节来学
3.1. 规则管理模式
Sentinel的控制台规则管理有三种模式
推送模式 | 说明 | 优点 | 缺点 |
原始模式 | API 将规则推送至客户端并直接更新到内存中,扩展写数据源,默认就是这种 | 简单,无任何依赖 | 不保证一致性;规则保存在内存中,重启即消失。严重不建议用于生产环境 |
Pull 模式 | 扩展写数据源,客户端主动向某个规则管理中心定时轮询拉取规则,,这个规则中心可以是RDBMS文件 | 简单,无任何依赖;规则持久化 | 不保证一致性;实时性不保证,拉取过于频繁也可能会有性能问题 |
Push 模式 | 扩展读数据源,规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 Nacos、Zookeeper 等配置中心。这种方式有更好的实时性和一致性保证。生产环境下一般采用 push 模式的数据源 | 规则持久化;一致性 | 引入第三方依赖 |
原始模式: 控制台配置的规则直接推送到Sentinel客户端,也就是我们的应用。然后保存在内存中,服务重启则丢失
pull模式: 控制台将配置的规则推送到Sentinel客户端,而客户端会将配置规则保存在本地文件或数据库中。以后会定时去本地文件或数据库中查询,更新本地规则
push模式: 控制台将配置规则推送到远程配置中心,例如Nacos。Sentinel客户端监听Nacos,获取配置变更的推送消息,完成本地配置更新
3.2. 实现push模式
push模式实现最为复杂,依赖于nacos,并且需要改在Sentinel控制台。整体步骤如下:
- 1、修改order-service服务,使其监听Nacos配置中心
- 2、修改Sentinel-dashboard源码,配置nacos数据源
- 3、修改Sentinel-dashboard源码修改前端页面
- 4、重新编译、打包-dashboard源码
具体操作如下
第一步: 在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-rulesgroupId: SENTINEL_GROUPrule-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模式,实现了规则持久化