怎么看网站用什么代码做的,wordpress 登录后台,爱站网权重查询,桂林软件开发#xff08;黑马出品_高级篇_01#xff09;SpringCloudRabbitMQDockerRedis搜索分布式 微服务技术——保护 今日目标1.初识Sentinel1.1.雪崩问题及解决方案1.2.服务保护技术对比1.3.Sentinel介绍和安装1.3.1.初识Sentinel1.3.2.安装Sentinel 1.… 黑马出品_高级篇_01SpringCloudRabbitMQDockerRedis搜索分布式 微服务技术——保护 今日目标1.初识Sentinel1.1.雪崩问题及解决方案1.2.服务保护技术对比1.3.Sentinel介绍和安装1.3.1.初识Sentinel1.3.2.安装Sentinel 1.4.微服务整合Sentinel 2.流量控制2.1.簇点链路2.1.快速入门2.2.流控模式2.2.1.关联模式2.2.2.链路模式2.2.3.总结 2.3.流控效果2.3.1.warm up1配置流控规则2Jmeter测试 2.3.2.排队等待1添加流控规则2Jmeter测试 2.3.3.总结 2.4.热点参数限流2.4.1.全局参数限流2.4.2.热点参数限流2.4.4.案例1标记资源2热点参数限流规则3Jmeter测试 3.隔离和降级3.1.FeignClient整合Sentinel3.1.1.修改配置开启sentinel功能3.1.2.编写失败降级逻辑3.1.3.总结 3.2.线程隔离舱壁模式3.2.1.线程隔离的实现方式3.2.2.sentinel的线程隔离1配置隔离规则2Jmeter测试 3.2.3.总结 3.3.熔断降级3.3.1.慢调用1设置慢调用2设置熔断规则3测试 3.3.2.异常比例、异常数1设置异常请求2设置熔断规则3测试 4.授权规则4.1.授权规则4.1.1.基本规则4.1.2.如何获取origin4.1.3.给网关添加请求头4.1.4.配置授权规则 4.2.自定义异常结果4.2.1.异常类型4.2.2.自定义异常处理 5.规则持久化5.1.规则管理模式5.1.1.pull模式5.1.2.push模式 5.2.实现push模式5.2.1 Sentinel 规则持久化一、修改order-service服务1.引入依赖2.配置nacos地址 二、修改sentinel-dashboard源码1\. 解压2\. 修改nacos依赖3\. 添加nacos支持4\. 修改nacos地址5\. 配置nacos数据源6\. 修改前端页面7\. 重新编译、打包项目8.启动 [此文档是在心向阳光的天域的博客加了一些有助于自己的知识体系也欢迎大家关注这个大佬的博客](https://blog.csdn.net/sinat_38316216/category_12263516.html) [是这个视频](https://www.bilibili.com/video/BV1LQ4y127n4/?p5spm_id_frompageDrivervd_source9beb0a2f0cec6f01c2433a881b54152c) 微服务技术——保护
今日目标 1.初识Sentinel
1.1.雪崩问题及解决方案
微服务中服务间调用关系错综复杂一个微服务往往依赖于多个其它微服务。
如图如果服务提供者I发生了故障当前的应用的部分业务因为依赖于服务I因此也会被阻塞。此时其它不依赖于服务I的业务似乎不受影响。 但是依赖服务I的业务请求被阻塞用户不会得到响应则tomcat的这个线程不会释放于是越来越多的用户请求到来越来越多的线程会阻塞 服务器支持的线程和并发数有限请求一直阻塞会导致服务器资源耗尽从而导致所有其它服务都不可用那么当前服务也就不可用了。
那么依赖于当前服务的其它服务随着时间的推移最终也都会变的不可用形成级联失败雪崩就发生了
雪崩微服务调用链路中的某个服务故障引起整个链路中的所有微服务都不可用这就是雪崩。 解决雪崩问题的常见方式有四种
方案1超时处理设定超时时间请求超过一定时间没有响应就返回错误信息不会无休止等待
仓壁模式
方案2仓壁模式
仓壁模式来源于船舱的设计
船舱都会被隔板分离为多个独立空间当船体破损时只会导致部分空间进入将故障控制在一定范围内避免整个船体都被淹没。
于此类似我们可以限定每个业务能使用的线程数避免耗尽整个tomcat的资源因此也叫线程隔离。
断路器
方案3断路器模式由断路器统计业务执行的异常比例如果超出阈值则会熔断该业务拦截访问该业务的一切请求。
断路器会统计访问某个服务的请求数量异常比例 当发现访问服务D的请求异常比例过高时认为服务D有导致雪崩的风险会拦截访问服务D的一切请求形成熔断
限流
方案4流量控制限制业务访问的QPS避免服务因流量的突增而故障。 什么是雪崩问题
微服务之间相互调用因为调用链中的一个服务故障引起整个链路都无法访问的情况。
可以认为
限流是对服务的保护避免因瞬间高并发流量而导致服务故障进而避免雪崩。是一种预防措施。
超时处理、线程隔离、降级熔断是在部分服务故障时将故障控制在一定范围避免雪崩。是一种补救措施。 1.2.服务保护技术对比
在SpringCloud当中支持多种服务保护技术
Netfix HystrixSentinelResilience4J
早期比较流行的是Hystrix框架但目前国内实用最广泛的还是阿里巴巴的Sentinel框架这里我们做下对比
SentinelHystrix隔离策略信号量隔离线程池隔离/信号量隔离熔断降级策略基于慢调用比例或异常比例基于失败比率实时指标实现滑动窗口滑动窗口基于 RxJava规则配置支持多种数据源支持多种数据源扩展性多个扩展点插件的形式基于注解的支持支持支持限流基于 QPS支持基于调用关系的限流有限的支持流量整形支持慢启动、匀速排队模式不支持系统自适应保护支持不支持控制台开箱即用可配置规则、查看秒级监控、机器发现等不完善常见框架的适配Servlet、Spring Cloud、Dubbo、gRPC 等Servlet、Spring Cloud Netflix 1.3.Sentinel介绍和安装
1.3.1.初识Sentinel
Sentinel是阿里巴巴开源的一款微服务流量控制组件。官网地址Sentinel官网
Sentinel 具有以下特征:
•丰富的应用场景Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景例如秒杀即突发流量控制在系统容量可以承受的范围、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
•完备的实时监控Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据甚至 500 台以下规模的集群的汇总运行情况。
•广泛的开源生态Sentinel 提供开箱即用的与其它开源框架/库的整合模块例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
•完善的 SPI 扩展点Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。
1.3.2.安装Sentinel
1下载
sentinel官方提供了UI控制台方便我们对系统做限流设置。大家可以在GitHub下载。
课前资料也提供了下载好的jar包
2运行
将jar包放到任意非中文目录
执行命令
java -jar sentinel-dashboard-1.8.1.jar如果要修改Sentinel的默认端口、账户、密码可以通过下列配置
配置项默认值说明server.port8080服务端口sentinel.dashboard.auth.usernamesentinel默认用户名sentinel.dashboard.auth.passwordsentinel默认密码
例如修改端口 java -D跟上以上三个请求即可 这里建议换一个端口
java -Dserver.port8099 -jar sentinel-dashboard-1.8.1.jar3访问
访问http://localhost:8099页面就可以看到sentinel的控制台了
需要输入账号和密码默认都是sentinel
登录后发现一片空白什么都没有 这是因为我们还没有与微服务整合。
1.4.微服务整合Sentinel 启动Nacos
./startup.cmd -m standalone启动后的效果图如下 在浏览器输入地址即可
http://127.0.0.1:8848/nacos默认的账号和密码都是nacos进入即可。
注意所有配置文件application.yml 中要从集群设置更改为本地配置 启动服务 启动成功后访问一下网关、Order和User,发现都无误即可
http://localhost:8081/user/1
http://localhost:8080/order/101
http://localhost:10010/user/1?authorizationadmin
http://localhost:10010/order/101?authorizationadmin我们在order-service中整合sentinel并连接sentinel的控制台步骤如下
1引入sentinel依赖
!--sentinel--
dependencygroupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-sentinel/artifactId
/dependency2配置控制台
修改application.yaml文件添加下面内容
server:port: 8080
spring:cloud: sentinel:transport:dashboard: localhost:8099配置好后重启order-service
3访问order-service的任意端点 打开浏览器访问http://localhost:8080/order/101这样才能触发sentinel的监控。 然后再访问sentinel的控制台查看效果
2.流量控制
雪崩问题虽然有四种方案但是限流是避免服务因突发的流量而发生故障是对微服务雪崩问题的预防。我们先学习这种模式。
2.1.簇点链路
当请求进入微服务时首先会访问DispatcherServlet然后进入Controller、Service、Mapper这样的一个调用链就叫做簇点链路。簇点链路中被监控的每一个接口就是一个资源。
默认情况下sentinel会监控SpringMVC的每一个端点Endpoint也就是controller中的方法因此SpringMVC的每一个端点Endpoint就是调用链路中的一个资源。
例如我们刚才访问的order-service中的OrderController中的端点/order/{orderId} 流控、熔断等都是针对簇点链路中的资源来设置的因此我们可以点击对应资源后面的按钮来设置规则
流控流量控制降级降级熔断热点热点参数限流是限流的一种授权请求的权限控制
2.1.快速入门
示例
点击资源/order/{orderId}后面的流控按钮就可以弹出表单。 表单中可以填写限流规则如下 其含义是限制 /order/{orderId}这个资源的单机QPS为1即每秒只允许1次请求超出的请求会被拦截并报错。
练习
需求给 /order/{orderId}这个资源设置流控规则QPS不能超过 5然后测试。
1首先在sentinel控制台添加限流规则 2利用jmeter测试 如果没有用过jmeter可以参考课前资料提供的文档《Jmeter快速入门.md》 打开JMeter
课前资料提供了编写好的Jmeter测试样例 打开jmeter导入课前资料提供的测试样例 选择 20个用户2秒内运行完QPS是10超过了5. 选中流控入门QPS5右键运行 注意不要点击菜单中的执行按钮来运行。 这里更改端口为order-service的端口8080
结果 可以看到成功的请求每次只有5个 查看失败原因 然后再去sentinel中查看调用情况
2.2.流控模式
在添加限流规则时点击高级选项可以选择三种流控模式
直接统计当前资源的请求触发阈值时对当前资源直接限流也是默认的模式关联统计与当前资源相关的另一个资源触发阈值时对当前资源限流链路统计从指定链路访问到本资源的请求触发阈值时对指定链路限流 快速入门测试的就是直接模式。
2.2.1.关联模式
关联模式统计与当前资源相关的另一个资源触发阈值时对当前资源限流 配置规则 语法说明当/write资源访问量触发阈值时就会对/read资源限流避免影响/write资源。
使用场景比如用户支付时需要修改订单状态同时用户要查询订单。查询和修改操作会争抢数据库锁产生竞争。业务需求是优先支付和更新订单的业务因此当修改订单业务触发阈值时需要对查询订单业务限流。
需求说明 在OrderController新建两个端点/order/query和/order/update无需实现业务 配置流控规则当/order/ update资源被访问的QPS超过5时对/order/query请求限流
1定义/order/query端点模拟订单查询
GetMapping(/query)
public String queryOrder() {return 查询订单成功;
}2定义/order/update端点模拟订单更新
GetMapping(/update)
public String updateOrder() {return 更新订单成功;
}重启服务访问一下新添加的地址
http://localhost:8080/order/query
http://localhost:8080/order/update查看sentinel控制台的簇点链路
3配置流控规则
对哪个端点限流就点击哪个端点后面的按钮。我们是对订单查询/order/query限流因此点击它后面的按钮 在表单中填写流控规则
4在Jmeter测试
选择《流控模式-关联》同理端口号更改为8080 可以看到1000个用户100秒因此QPS为10超过了我们设定的阈值5
查看http请求 请求的目标是/order/update这样这个断点就会触发阈值。
但限流的目标是/order/query我们在浏览器访问可以发现 确实被限流了。
5总结
2.2.2.链路模式
链路模式只针对从指定链路访问到本资源的请求做统计判断是否超过阈值。 配置示例
例如有两条请求链路
/test1 -- /common/test2 -- /common
如果只希望统计从/test2进入到/common的请求则可以这样配置 实战案例
需求有查询订单和创建订单业务两者都需要查询商品。针对从查询订单进入到查询商品的请求统计并设置限流。
步骤
在OrderService中添加一个queryGoods方法不用实现业务在OrderController中改造/order/query端点调用OrderService中的queryGoods方法在OrderController中添加一个/order/save的端点调用OrderService的queryGoods方法给queryGoods设置限流规则从/order/query进入queryGoods的方法限制QPS必须小于2
实现
1添加查询商品方法
在order-service服务中给OrderService类添加一个queryGoods方法
public void queryGoods(){System.err.println(查询商品);
}2查询订单时查询商品
在order-service的OrderController中修改/order/query端点的业务逻辑
GetMapping(/query)
public String queryOrder() {// 查询商品orderService.queryGoods();// 查询订单System.out.println(查询订单);return 查询订单成功;
}3新增订单查询商品
在order-service的OrderController中修改/order/save端点模拟新增订单
GetMapping(/save)
public String saveOrder() {// 查询商品orderService.queryGoods();// 查询订单System.err.println(新增订单);return 新增订单成功;
}4给查询商品添加资源标记
默认情况下OrderService中的方法是不被Sentinel监控的需要我们自己通过注解来标记要监控的方法。 给OrderService的queryGoods方法添加**SentinelResource**注解
SentinelResource(goods)
public void queryGoods(){System.err.println(查询商品);
}链路模式中是对不同来源的两个链路做监控。但是sentinel默认会给进入SpringMVC的所有请求设置同一个root资源会导致链路模式失效。
我们需要关闭这种对SpringMVC的资源聚合修改order-service服务的application.yml文件
spring:cloud:sentinel:web-context-unify: false # 关闭context整合重启服务访问/order/query和/order/save
可以查看到sentinel的簇点链路规则中出现了新的资源 5添加流控规则
点击goods资源后面的流控按钮在弹出的表单中填写下面信息 只统计从/order/query进入/goods的资源QPS阈值为2超出则被限流。 6Jmeter测试
选择《流控模式-链路》 可以看到这里200个用户50秒内发完QPS为4超过了我们设定的阈值2 一个http请求是访问/order/save 运行的结果 完全不受影响。 另一个是访问/order/query 运行结果 每次只有2个通过。
2.2.3.总结
流控模式有哪些
•直接对当前资源限流
•关联高优先级资源触发阈值对低优先级资源限流。
•链路阈值统计时只统计从指定资源进入当前资源的请求是对请求来源的限流 2.3.流控效果
在流控的高级选项中还有一个流控效果选项 流控效果是指请求达到流控阈值时应该采取的措施包括三种 快速失败达到阈值后新的请求会被立即拒绝并抛出FlowException异常。是默认的处理方式。 warm up预热模式对超出阈值的请求同样是拒绝并抛出异常。但这种模式阈值会动态变化从一个较小值逐渐增加到最大阈值。 排队等待让所有的请求按照先后次序排队执行两个请求的间隔不能小于指定时长
2.3.1.warm up
阈值一般是一个微服务能承担的最大QPS但是一个服务刚刚启动时一切资源尚未初始化冷启动如果直接将QPS跑到最大值可能导致服务瞬间宕机。
warm up也叫预热模式是应对服务冷启动的一种方案。请求阈值初始值是 maxThreshold / coldFactor持续指定时长后逐渐提高到maxThreshold值。而coldFactor的默认值是3.
例如我设置QPS的maxThreshold为10预热时间为5秒那么初始阈值就是 10 / 3 也就是3然后在5秒后逐渐增长到10. 案例 先访问
http://localhost:8080/order/101需求给/order/{orderId}这个资源设置限流最大QPS为10利用warm up效果预热时长为5秒
1配置流控规则 2Jmeter测试
选择《流控效果warm up》
QPS为10.
刚刚启动时大部分请求失败成功的只有3个说明QPS被限定在3 随着时间推移成功比例越来越高 到Sentinel控制台查看实时监控 一段时间后
2.3.2.排队等待
当请求超过QPS阈值时快速失败和warm up 会拒绝新的请求并抛出异常。 而排队等待则是让所有请求进入一个队列中然后按照阈值允许的时间间隔依次执行。后来的请求必须等待前面执行完成如果请求预期的等待时间超出最大时长则会被拒绝。
工作原理
例如QPS 5意味着每200ms处理一个队列中的请求timeout 2000意味着预期等待时长超过2000ms的请求会被拒绝并抛出异常。 那什么叫做预期等待时长呢
比如现在一下子来了12 个请求因为每200ms执行一个请求那么
第6个请求的预期等待时长 200 * 6 - 1 1000ms第12个请求的预期等待时长 200 * 12-1 2200ms
现在第1秒同时接收到10个请求但第2秒只有1个请求此时QPS的曲线这样的
如果使用队列模式做流控所有进入的请求都要排队以固定的200ms的间隔执行QPS会变的很平滑
平滑的QPS曲线对于服务器来说是更友好的。
案例
需求给/order/{orderId}这个资源设置限流最大QPS为10利用排队的流控效果超时时长设置为5s
1添加流控规则 2Jmeter测试
选择《流控效果队列》 QPS为15已经超过了我们设定的10。
如果是之前的 快速失败、warmup模式超出的请求应该会直接报错。
但是我们看看队列模式的运行结果 全部都通过了。
再去sentinel查看实时监控的QPS曲线
QPS非常平滑一致保持在10但是超出的请求没有被拒绝而是放入队列。因此响应时间等待时间会越来越长。 当队列满了以后才会有部分请求失败
2.3.3.总结
流控效果有哪些
快速失败QPS超过阈值时拒绝新的请求warm up QPS超过阈值时拒绝新的请求QPS阈值是逐渐提升的可以避免冷启动时高并发导致服务宕机。排队等待请求会进入队列按照阈值允许的时间间隔依次执行请求如果请求预期等待时长大于超时时间直接拒绝 2.4.热点参数限流
之前的限流是统计访问某个资源的所有请求判断是否超过QPS阈值。而热点参数限流是分别统计参数值相同的请求判断是否超过QPS阈值。
2.4.1.全局参数限流
例如一个根据id查询商品的接口 访问/goods/{id}的请求中id参数值会有变化热点参数限流会根据参数值分别统计QPS统计结果 当id1的请求触发阈值被限流时id值不为1的请求不受影响。
配置示例 代表的含义是对hot这个资源的0号参数第一个参数做统计每1秒相同参数值的请求数不能超过5
2.4.2.热点参数限流
刚才的配置中对查询商品这个接口的所有商品一视同仁QPS都限定为5.
而在实际开发中可能部分商品是热点商品例如秒杀商品我们希望这部分商品的QPS限制与其它商品不一样高一些。那就需要配置热点参数限流的高级选项了 结合上一个配置这里的含义是对0号的long类型参数限流每1秒相同参数的QPS不能超过5有两个例外
•如果参数值是100则每1秒允许的QPS为10 •如果参数值是101则每1秒允许的QPS为15
2.4.4.案例
案例需求给/order/{orderId}这个资源添加热点参数限流规则如下
默认的热点参数规则是每1秒请求量不超过2给102这个参数设置例外每1秒请求量不超过4给103这个参数设置例外每1秒请求量不超过10
注意事项热点参数限流对默认的SpringMVC资源无效需要利用SentinelResource注解标记资源
1标记资源
给order-service中的OrderController中的/order/{orderId}资源添加注解 修改完之后记得重启一下order-service服务
2热点参数限流规则
访问该接口可以看到我们标记的hot资源出现了 这里不要点击hot后面的按钮页面有BUG
点击左侧菜单中热点规则菜单 点击新增填写表单
3Jmeter测试
选择《热点参数限流 QPS1》 这里发起请求的QPS为5.
包含3个http请求
普通参数QPS阈值为2 运行结果 例外项QPS阈值为4
运行结果
例外项QPS阈值为10
运行结果
3.隔离和降级
限流是一种预防措施虽然限流可以尽量避免因高并发而引起的服务故障但服务还会因为其它原因而故障。
而要将这些故障控制在一定范围避免雪崩就要靠线程隔离舱壁模式和熔断降级手段了。
线程隔离之前讲到过调用者在调用服务提供者时给每个调用的请求分配独立线程池出现故障时最多消耗这个线程池内资源避免把调用者的所有资源耗尽。
熔断降级是在调用方这边加入断路器统计对服务提供者的调用如果调用的失败比例过高则熔断该业务不允许访问该服务的提供者了。
可以看到不管是线程隔离还是熔断降级都是对客户端调用方的保护。需要在调用方 发起远程调用时做线程隔离、或者服务熔断。
而我们的微服务远程调用都是基于Feign来完成的因此我们需要将Feign与Sentinel整合在Feign里面实现线程隔离和服务熔断。
3.1.FeignClient整合Sentinel
SpringCloud中微服务调用都是通过Feign来实现的因此做客户端保护必须整合Feign和Sentinel。
3.1.1.修改配置开启sentinel功能
修改OrderService的application.yml文件开启Feign的Sentinel功能
feign:sentinel:enabled: true # 开启feign对sentinel的支持3.1.2.编写失败降级逻辑
业务失败后不能直接报错而应该返回用户一个友好提示或者默认结果这个就是失败降级逻辑。
给FeignClient编写失败后的降级逻辑
方式一FallbackClass无法对远程调用的异常做处理方式二FallbackFactory可以对远程调用的异常做处理我们选择这种
这里我们演示方式二的失败降级处理。
步骤一在feing-api项目中定义类实现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;Slf4j
public class UserClientFallbackFactory implements FallbackFactoryUserClient {Overridepublic UserClient create(Throwable throwable) {return new UserClient() {Overridepublic User findById(Long id) {log.error(查询用户异常, throwable);// 根据业务需求返回默认的数据例如这里返回了空用户return new User();}};}
}
步骤二在feing-api项目中的DefaultFeignConfiguration类中将UserClientFallbackFactory注册为一个Bean
Bean
public UserClientFallbackFactory userClientFallbackFactory(){return new UserClientFallbackFactory();
}步骤三在feing-api项目中的UserClient接口中使用UserClientFallbackFactory
import cn.itcast.feign.clients.fallback.UserClientFallbackFactory;
import cn.itcast.feign.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;FeignClient(value userservice, fallbackFactory UserClientFallbackFactory.class)
public interface UserClient {GetMapping(/user/{id})User findById(PathVariable(id) Long id);
}重启服务后访问一次订单查询业务然后查看sentinel控制台可以看到新的簇点链路
3.1.3.总结
Sentinel支持的雪崩解决方案
线程隔离仓壁模式降级熔断
Feign整合Sentinel的步骤
在application.yml中配置feign.sentienl.enabletrue给FeignClient编写FallbackFactory并注册为Bean将FallbackFactory配置到FeignClient 3.2.线程隔离舱壁模式
3.2.1.线程隔离的实现方式
线程隔离有两种方式实现 线程池隔离 信号量隔离Sentinel默认采用
如图 线程池隔离给每个服务调用业务分配一个线程池利用线程池本身实现隔离效果
信号量隔离不创建线程池而是计数器模式记录业务使用的线程数量达到信号量上限时禁止新的请求。
两者的优缺点 3.2.2.sentinel的线程隔离
用法说明
在添加限流规则时可以选择两种阈值类型 QPS就是每秒的请求数在快速入门中已经演示过 线程数是该资源能使用用的tomcat线程数的最大值。也就是通过限制线程数量实现线程隔离舱壁模式。
案例需求给 order-service服务中的UserClient的查询用户接口设置流控规则线程数不能超过 2。然后利用jemeter测试。
1配置隔离规则
选择feign接口后面的流控按钮
填写表单
2Jmeter测试
选择《阈值类型-线程数2》 一次发生10个请求有较大概率并发线程数超过2而超出的请求会走之前定义的失败降级逻辑。
查看运行结果
发现虽然结果都是通过了不过部分请求得到的响应是降级返回的null信息。
3.2.3.总结
线程隔离的两种手段是 信号量隔离 线程池隔离
信号量隔离的特点是
基于计数器模式简单开销小
线程池隔离的特点是
基于线程池模式有额外开销但隔离控制更强 3.3.熔断降级
熔断降级是解决雪崩问题的重要手段。其思路是由断路器统计服务调用的异常比例、慢请求比例如果超出阈值则会熔断该服务。即拦截访问该服务的一切请求而当服务恢复时断路器会放行访问该服务的请求。
断路器控制熔断和放行是通过状态机来完成的 状态机包括三个状态
closed关闭状态断路器放行所有请求并开始统计异常比例、慢请求比例。超过阈值则切换到open状态open打开状态服务调用被熔断访问被熔断服务的请求会被拒绝快速失败直接走降级逻辑。Open状态5秒后会进入half-open状态half-open半开状态放行一次请求根据执行结果来判断接下来的操作。 请求成功则切换到closed状态请求失败则切换到open状态
断路器熔断策略有三种慢调用、异常比例、异常数
3.3.1.慢调用
慢调用业务的响应时长RT大于指定时长的请求认定为慢调用请求。在指定时间内如果请求数量超过设定的最小数量慢调用比例大于设定的阈值则触发熔断。
例如
解读RT超过500ms的调用是慢调用统计最近10000ms内的请求如果请求量超过10次并且慢调用比例不低于0.5则触发熔断熔断时长为5秒。然后进入half-open状态放行一次请求做测试。
案例 需求给 UserClient的查询用户接口设置降级规则慢调用的RT阈值为50ms统计时间为1秒最小请求数量为5失败阈值比例为0.4熔断时长为5
1设置慢调用
修改user-service中的/user/{id}这个接口的业务。通过休眠模拟一个延迟时间 此时orderId101的订单关联的是id为1的用户调用时长为60ms orderId102的订单关联的是id为2的用户调用时长为非常短
2设置熔断规则
先删除之前的流控规则防止产生影响 下面给feign接口设置降级规则 规则 超过50ms的请求都会被认为是慢请求
3测试
在浏览器访问http://localhost:8088/order/101快速刷新5次可以发现 触发了熔断请求时长缩短至5ms快速失败了并且走降级逻辑返回的null
在浏览器访问http://localhost:8088/order/102竟然也被熔断了 3.3.2.异常比例、异常数
异常比例或异常数统计指定时间内的调用如果调用次数超过指定请求数并且出现异常的比例达到设定的比例阈值或超过指定异常数则触发熔断。
例如一个异常比例设置
解读统计最近1000ms内的请求如果请求量超过10次并且异常比例不低于0.4则触发熔断。
一个异常数设置 解读统计最近1000ms内的请求如果请求量超过10次并且异常比例不低于2次则触发熔断。
案例
需求给 UserClient的查询用户接口设置降级规则统计时间为1秒最小请求数量为5失败阈值比例为0.4熔断时长为5s
1设置异常请求
首先修改user-service中的/user/{id}这个接口的业务。手动抛出异常以触发异常比例的熔断 也就是说id 为 2时就会触发异常 我们访问一下
http://localhost:8080/order/102抛出异常
2设置熔断规则
删除之前的熔断规则
下面给feign接口设置降级规则 规则 在5次请求中只要异常比例超过0.4也就是有2次以上的异常就会触发熔断。
3测试
在浏览器快速访问http://localhost:8088/order/102快速刷新5次触发熔断 此时我们去访问本来应该正常的103 总结 Sentinel熔断降级的策略有哪些?
慢调用比例: 超过指定时长的调用为慢调用统计单位时长内 慢调用的比例超过阈值则熔断异常比例:统计单位时长内异常调用的比例超过阈值则熔断异常数:统计单位时长内异常调用的次数超过阈值则熔断 4.授权规则
授权规则可以对请求方来源做判断和控制。
4.1.授权规则
4.1.1.基本规则
授权规则可以对调用方的来源做控制有白名单和黑名单两种方式。 白名单来源origin在白名单内的调用者允许访问 黑名单来源origin在黑名单内的调用者不允许访问
点击左侧菜单的授权可以看到授权规则 资源名就是受保护的资源例如/order/{orderId} 流控应用是来源者的名单 如果是勾选白名单则名单中的来源被许可访问。如果是勾选黑名单则名单中的来源被禁止访问。
比如
我们允许请求从gateway到order-service不允许浏览器访问order-service那么白名单中就要填写网关的来源名称origin。
4.1.2.如何获取origin
Sentinel是通过RequestOriginParser这个接口的parseOrigin来获取请求的来源的。
public interface RequestOriginParser {/*** 从请求request对象中获取origin获取方式自定义*/String parseOrigin(HttpServletRequest request);
}这个方法的作用就是从request对象中获取请求者的origin值并返回。
默认情况下sentinel不管请求者从哪里来返回值永远是default也就是说一切请求的来源都被认为是一样的值default。
因此我们需要自定义这个接口的实现让不同的请求返回不同的origin。
例如order-service服务中我们定义一个RequestOriginParser的实现类
package cn.itcast.order.sentinel;import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;import javax.servlet.http.HttpServletRequest;Component
public class HeaderOriginParser implements RequestOriginParser {Overridepublic String parseOrigin(HttpServletRequest request) {// 1.获取请求头String origin request.getHeader(origin);// 2.非空判断if (StringUtils.isEmpty(origin)) {origin blank;}return origin;}
}我们会尝试从request-header中获取origin值。
4.1.3.给网关添加请求头
既然获取请求origin的方式是从reques-header中获取origin值我们必须让所有从gateway路由到微服务的请求都带上origin头。
这个需要利用之前学习的一个GatewayFilter来实现AddRequestHeaderGatewayFilter。
修改gateway服务中的application.yml添加一个defaultFilter
spring:cloud:gateway:default-filters:- AddRequestHeaderorigin,gatewayroutes:# ...略这样从gateway路由的所有请求都会带上origin头值为gateway。而从其它地方到达微服务的请求则没有这个头。
配置完后我们重启Gateway和OrderService 访问
http://localhost:8080/order/1034.1.4.配置授权规则
接下来我们添加一个授权规则放行origin值为gateway的请求。 配置如下 现在我们直接跳过网关访问order-service服务 通过网关访问
我们访问
http://localhost:8080/order/102发现直接报错了 而我们访问网关
http://localhost:10010/order/101?authorizationadmin发现访问无误
4.2.自定义异常结果
默认情况下发生限流、降级、授权拦截时都会抛出异常到调用方。异常结果都是flow limmiting限流。这样不够友好无法得知是限流还是降级还是授权拦截。
4.2.1.异常类型
而如果要自定义异常时的返回结果需要实现BlockExceptionHandler接口
public interface BlockExceptionHandler {/*** 处理请求被限流、降级、授权拦截时抛出的异常BlockException*/void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception;
}这个方法有三个参数
HttpServletRequest requestrequest对象HttpServletResponse responseresponse对象BlockException e被sentinel拦截时抛出的异常
这里的BlockException包含多个不同的子类
异常说明FlowException限流异常ParamFlowException热点参数限流的异常DegradeException降级异常AuthorityException授权规则异常SystemBlockException系统规则异常
4.2.2.自定义异常处理
下面我们就在order-service定义一个自定义异常处理类
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
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;charsetutf-8);response.setStatus(status);response.getWriter().println({\msg\: msg , \status\: status });}
}重启测试在不同场景下会返回不同的异常消息. 先添加流控规则设置QPS 1 这里重启一下idea清理缓存 访问
http://localhost:8080/order/103限流
上面规则测试完之后记得删除然后配置授权规则
授权拦截时 再此访问
http://localhost:8080/order/1035.规则持久化
现在sentinel的所有规则都是内存存储重启后所有规则都会丢失。在生产环境下我们必须确保这些规则的持久化避免丢失。
5.1.规则管理模式
规则是否能持久化取决于规则管理模式sentinel支持三种规则管理模式
原始模式Sentinel的默认模式将规则保存在内存重启服务会丢失。pull模式push模式
5.1.1.pull模式
pull模式控制台将配置的规则推送到Sentinel客户端而客户端会将配置规则保存在本地文件或数据库中。以后会定时去本地文件或数据库中查询更新本地规则。 缺点存在时效性问题会有数据不一致问题
5.1.2.push模式
push模式控制台将配置规则推送到远程配置中心例如Nacos。Sentinel客户端监听Nacos获取配置变更的推送消息完成本地配置更新。 5.2.实现push模式
详细步骤可以参考课前资料的《sentinel规则持久化》
5.2.1 Sentinel 规则持久化
一、修改order-service服务
修改OrderService让其监听Nacos中的sentinel规则配置。 具体步骤如下
1.引入依赖
在order-service中引入sentinel监听nacos的依赖
dependencygroupIdcom.alibaba.csp/groupIdartifactIdsentinel-datasource-nacos/artifactId
/dependency2.配置nacos地址
在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修改完后重启order-service项目
二、修改sentinel-dashboard源码
SentinelDashboard默认不支持nacos的持久化需要修改源码。
1. 解压
解压课前资料中的sentinel源码包 然后并用IDEA打开这个项目结构如下
2. 修改nacos依赖
在sentinel-dashboard源码的pom文件中nacos的依赖默认的scope是test只能在测试时使用这里要去除 将sentinel-datasource-nacos依赖的scope去掉
dependencygroupIdcom.alibaba.csp/groupIdartifactIdsentinel-datasource-nacos/artifactId
/dependency3. 添加nacos支持
在sentinel-dashboard的test包下已经编写了对nacos的支持我们需要将其拷贝到main下。
4. 修改nacos地址
然后还需要修改测试代码中的NacosConfig类
修改其中的nacos地址让其读取application.properties中的配置 在sentinel-dashboard的application.properties中添加nacos地址配置
nacos.addrlocalhost:88485. 配置nacos数据源
另外还需要修改com.alibaba.csp.sentinel.dashboard.controller.v2包下的FlowControllerV2类 让我们添加的Nacos数据源生效
6. 修改前端页面
接下来还要修改前端页面添加一个支持nacos的菜单。
修改src/main/webapp/resources/app/scripts/directives/sidebar/目录下的sidebar.html文件
将其中的这部分注释打开
修改其中的文本
7. 重新编译、打包项目
运行IDEA中的maven插件编译和打包修改好的Sentinel-Dashboard
8.启动
启动方式跟官方一样
java -jar sentinel-dashboard.jar如果要修改nacos地址需要添加参数 这里我们用项目资料中老师打包好的 更改order-service的配置文件的端口,因为老师的jar包是8080端口
之后启动jar包
java -jar -Dnacos.addrlocalhost:8848 sentinel-dashboard.jar打开浏览器访问登录sentinel
http://localhost:8080/#/login先访问加载簇点链路
http://localhost:8088/order/103刷新sentinel(这里可以重启一下IDEA) 访问
http://localhost:8080/#/dashboard清楚后重新登录sentinel发现多了流控规则 点击新增流控规则
资源名
/order/{orderId}访问
http://localhost:8848/nacos/发现多出来了一条配置列表正是我们的限流规则 访问2次
http://localhost:8088/order/101我们重启IDEA看一下限流规则消失没 再2次访问
http://localhost:8088/order/101发现限流规则没有消失实现了持久化