SpringCloud Alibaba系列文章列表
0. SpringCloud Alibaba入门简介
1. SpringCloud Alibaba Nacos 之 服务注册中心
2. SpringCloud Alibaba Nacos 之 服务配置中心
3. SpringCloud Alibaba Nacos 之 集群
4. SpringCloud Alibaba Sentinel 服务限流熔断(万字长文)
文章目录
官方网址
https://github.com/alibaba/Sentinel
中文文档
https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D
下载
https://github.com/alibaba/Sentinel/releases
1. Sentinel是什么?
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
Sentinel 具有以下特征:
- 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
- 完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
- 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
- 完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。
Sentinel 的主要特性:
Sentinel 分为两个部分:
- 核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。
- 控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。
2. Sentinel 控制台
https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0
2.1 概述
Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能。另外,鉴权在生产环境中也必不可少。
2.2 下载
直接下载jar 或者 下载工程自己打包
https://github.com/alibaba/Sentinel/releases
我下载的是 sentinel-dashboard-1.8.0.jar
2.3 启动
注意:启动 Sentinel 控制台需要 JDK 版本为 1.8 及以上版本。
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
其中 -Dserver.port=8080
用于指定 Sentinel 控制台端口为 8080
。
-Dcsp.sentinel.dashboard.server=consoleIp:port
指定控制台地址和端口
若启动多个应用,则需要通过 -Dcsp.sentinel.api.port=xxxx
指定客户端监控 API 的端口(默认是 8719)。
从 Sentinel 1.6.0 起,Sentinel 控制台引入基本的登录功能,默认用户名和密码都是 sentinel
2.4 访问
http://localhost:8080/
3. 客户端接入demo
参考 Spring Cloud Alibaba Sentinel https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel
-
pom.xml
<!--alibaba-sentinel--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> <!--web--> <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>
-
application.yml
server: port: 8401 spring: application: name: sentinel-service cloud: sentinel: transport: dashboard: localhost:8080 # sentinel控制台地址 port: 8719 #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口
-
启动类
无额外注解
-
业务类 TestController
@RestController public class TestController { @GetMapping("/testA") public String testA() { return "------testA"; } @GetMapping("/testB") public String testB() { return "------testB"; } }
-
测试
确保客户端有访问量,Sentinel 会在客户端首次调用的时候进行初始化,开始向控制台发送心跳包。
先启动sentinel控制台,然后启动cloudalibaba-sentinel-service8401项目
浏览器访问接口http://localhost:8401/testA
访问控制台查看如下图,服务监控成功
多次访问http://localhost:8401/testA 和 http://localhost:8401/testB
可以看到接口实时QPS监控
4. 规则的种类
https://github.com/alibaba/Sentinel/wiki/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8#%E8%A7%84%E5%88%99%E7%9A%84%E7%A7%8D%E7%B1%BB
Sentinel 的所有规则都可以在内存态中动态地查询及修改,修改之后立即生效。同时 Sentinel 也提供相关 API,供您来定制自己的规则策略。
Sentinel 支持以下几种规则:流量控制规则、熔断降级规则、系统保护规则、来源访问控制规则 和 热点参数规则。
4.1 流量控制规则 (FlowRule)
流量控制(flow control),其原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。
重要属性:
Field | 说明 | 默认值 |
---|---|---|
resource | 资源名,资源名是限流规则的作用对象 | |
count | 限流阈值 | |
grade | 限流阈值类型,QPS 模式(1)或并发线程数模式(0) | QPS 模式 |
limitApp | 流控针对的调用来源 | default ,代表不区分调用来源 |
strategy | 调用关系限流策略:直接、链路、关联 | 根据资源本身(直接) |
controlBehavior | 流控效果(直接拒绝/WarmUp/匀速+排队等待),不支持按调用关系限流 | 直接拒绝 |
clusterMode | 是否集群限流 | 否 |
同一个资源可以同时有多个限流规则,检查规则时会依次检查。
进一步解释:
- 资源名:唯一名称,默认请求路径
- 针对来源:Sentinel可以针对调用者进行限流,填写微服务名,默认default (不区分来源)
- 阈值类型/单机阈值:
- QPS(每秒钟的请求数量):当调用该API的QPS达到阈值的时候,进行限流
- 线程数:当调用该api的线程数达到阈值的时候,进行限流
- 流控模式
- 直接:API达到限流条件时,直接限流
- 关联:当关联的资源达到阈值时,就限流自己
- 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)
- 流控效果
- 快速失败:直接失败,抛异常
- Warm Up:根据codeFactor(冷加载因子,默认3)的值,从阈值除以codeFactor,经过预热时长,才达到设置的QPS阈值
- 排队等待:匀速排队,让请求以均匀的速度通过
后面将举例介绍不同组合的限流效果;
4.1.1 QPS快速失败
在簇点链路中,选择/testA资源,点击增加流控按钮(得先访问该接口产生流量,才能看到该链路)
或者直接在流控规则中点击添加
如上图,单机阈值设为1;即每秒内的请求数量不能超过1,否则限流;
点击新增后,可以在流控规则菜单下看到新生成的规则;可以进行编辑、删除操作;
浏览器快速访问 http://localhost:8401/testA
返回默认的报错提示 Blocked by Sentinel (flow limiting), 限流成功;
4.1.2 线程数快速失败
修改testA方法,在方法内部阻塞3s后再返回结果;防止执行过快,看不出并发阻塞效果;
重启项目后,需要重新配置testA的流控规则如下图:即同时只有一个线程能够调用该方法
借助jmeter进行测试,设置3个线程数,每个线程调用一次;
结果只有一个线程调用成功,另外两个报错被限流了;
4.1.3 关联
测试案例:如下图, /testB添加流控规则,关联/testA, 即 当/testA的QPS阈值超过1时,/testB限流
借助jmeter测试,10个线程,每个线程1000次 访问/testA;同时访问/testB,发现/testB限流
4.1.4 链路
//TODO
4.1.5 Warm Up 预热
https://github.com/alibaba/Sentinel/wiki/%E9%99%90%E6%B5%81—%E5%86%B7%E5%90%AF%E5%8A%A8
当流量突然增大的时候,我们常常会希望系统从空闲状态到繁忙状态的切换的时间长一些。即如果系统在此之前长期处于空闲的状态,我们希望处理请求的数量是缓步的增多,经过预期的时间以后,到达系统处理请求个数的最大值。Warm Up(冷启动,预热)模式就是为了实现这个目的的。
这个场景主要用于启动需要额外开销的场景,例如建立数据库连接等。
计算公式: 默认 coldFactor
(冷加载因子) 为 3,即请求 QPS 从 threshold / 3
开始,经预热时长逐渐升至设定的 QPS 阈值,进行限流。(threshold为阈值)
如下图,即QPS的阈值从 10/3 开始,5s内逐渐变成10
测试:现象就是 快速访问/testA,发现刚开始限流,5s后就不限流了;
4.1.6 排队等待
https://github.com/alibaba/Sentinel/wiki/%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6-%E5%8C%80%E9%80%9F%E6%8E%92%E9%98%9F%E6%A8%A1%E5%BC%8F
这种方式适合用于请求以突刺状来到,这个时候我们不希望一下子把所有的请求都通过,这样可能会把系统压垮;同时我们也期待系统以稳定的速度,逐步处理这些请求,以起到“削峰填谷”的效果,而不是拒绝所有请求。
给/testA配置流控规则,超时时间配大点保证所有请求能通过,阈值设为2,即每秒钟通过两个请求,所有请求排队匀速通过;
修改testA方法,打印出当前时间,便于验证
@GetMapping("/testA")
public String testA() {
System.out.println("/testA>>>"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
return "------testA"+System.currentTimeMillis();
}
借助jmeter, 1个线程,1000个请求
执行后查看日志,发现1s中两个请求,可见是匀速排队通过的;
4.2 熔断降级规则 (DegradeRule)
https://github.com/alibaba/Sentinel/wiki/%E7%86%94%E6%96%AD%E9%99%8D%E7%BA%A7
Sentinel 1.8.0 及以上版本,对熔断降级特性进行了全新的改进升级
4.2.1 概述
除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。一个服务常常会调用别的模块,可能是另外的一个远程服务、数据库,或者第三方 API 等。例如,支付的时候,可能需要远程调用银联提供的 API;查询某个商品的价格,可能需要进行数据库查询。然而,这个被依赖服务的稳定性是不能保证的。如果依赖的服务出现了不稳定的情况,请求的响应时间变长,那么调用服务的方法的响应时间也会变长,线程会产生堆积,最终可能耗尽业务自身的线程池,服务本身也变得不可用。
现代微服务架构都是分布式的,由非常多的服务组成。不同服务之间相互调用,组成复杂的调用链路。以上的问题在链路调用中会产生放大的效果。复杂链路上的某一环不稳定,就可能会层层级联,最终导致整个链路都不可用。因此我们需要对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩。熔断降级作为保护自身的手段,通常在客户端(调用端)
进行配置。
4.2.2 熔断策略
Sentinel 提供以下几种熔断策略:
- 慢调用比例 (
SLOW_REQUEST_RATIO
):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs
)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。 - 异常比例 (
ERROR_RATIO
):当单位统计时长(statIntervalMs
)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是[0.0, 1.0]
,代表 0% - 100%。 - 异常数 (
ERROR_COUNT
):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。
4.2.2.1 慢调用比例
新增方法用于测试,传入时间参数,便于接口定义为慢接口
@GetMapping("/testRT")
public String testRT(Integer time) {
if(null != time){//sleep指定时间
try {
TimeUnit.SECONDS.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("time:"+time+" ,/testRT>>>"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
return "------testRT";
}
配置如下:
当响应时间大于1s则为慢请求,当请求数量>5并且全是慢请求,则接下来5s内的请求自动被熔断。5s后,进入探测恢复状态(HALF-OPEN 状态),若接下来的请求不是慢请求,则熔断结束,否则继续熔断。
借助jmeter测试, 1s内1个线程访问10次 , http://127.0.0.1:8401/testRT?time=2
再进入熔断状态后,地址栏同时快速访问 http://127.0.0.1:8401/testRT (非慢查询)
结果如下:
5次调用后,进入熔断状态;浏览器访问返回 Blocked by Sentinel (flow limiting)
日志:
查看日志发现,熔断后5s,开始恢复正常;
ps: 实际测试过程中,发现 慢调用比例阈值 好像不太好用,你们多试试吧
4.2.2.2 异常比例
当单位统计时长内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断;
如下图: 连续6个请求异常的比例为1及全部异常,则接下来的请求被熔断;
新增方法testRT2进行测试
@GetMapping("/testRT2")
public String testRT2(Integer num) {
int i = 10/num;
System.out.println("/testRT2>>>"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
return "------testRT2";
}
借助jmeter,设置1个线程跑10次,访问 http://127.0.0.1:8401/testRT2?num=0
结论:6次请求全部异常,达到阈值,断路器开启进入熔断,接下来的请求5s内不再报错,而是服务降级。
其它阈值,可能自己测测;例如jmeter建一个线程组,跑两个请求,一个正常请求,一个异常请求;看看是否会进入熔断;
4.2.2.3 异常数
当单位统计时长内的异常数目超过阈值之后会自动进行熔断。
添加如下图:
浏览器快速访问 http://127.0.0.1:8401/testRT2?num=0,发现第二个请求后就进入熔断状态。
4.3 系统保护规则 (SystemRule)
https://github.com/alibaba/Sentinel/wiki/%E7%B3%BB%E7%BB%9F%E8%87%AA%E9%80%82%E5%BA%94%E9%99%90%E6%B5%81
4.3.1 概述
系统保护规则是从应用级别的入口流量进行控制,从单台机器的 load、CPU 使用率、平均 RT、入口 QPS 和并发线程数等几个维度监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(EntryType.IN
),比如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。
系统规则支持以下的模式:
- Load 自适应(仅对 Linux/Unix-like 机器生效):系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的
maxQps * minRt
估算得出。设定参考值一般是CPU cores * 2.5
。 - CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。
- 平均 RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
- 并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
- 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。
4.3.2 演示
配置如下图,发现所有接口QPS > 1,都限流
4.4 访问控制规则 / 黑白名单控制 (AuthorityRule)
黑白名单控制
https://github.com/alibaba/Sentinel/wiki/%E9%BB%91%E7%99%BD%E5%90%8D%E5%8D%95%E6%8E%A7%E5%88%B6
4.4.1 概述
很多时候,我们需要根据调用来源来判断该次请求是否允许放行,这时候可以使用 Sentinel 的来源访问控制(黑白名单控制)的功能。来源访问控制根据资源的请求来源(origin
)限制资源是否通过,若配置白名单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。
调用方信息通过
ContextUtil.enter(resourceName, origin)
方法中的origin
参数传入。
4.4.2 配置规则
来源访问控制规则(AuthorityRule
)非常简单,主要有以下配置项:
resource
:资源名,即限流规则的作用对象。limitApp
:对应的黑名单/白名单,不同 origin 用,
分隔,如appA,appB
。strategy
:限制模式,AUTHORITY_WHITE
为白名单模式,AUTHORITY_BLACK
为黑名单模式,默认为白名单模式。
4.4.3 示例
Sentinel提供了 RequestOriginParser 接口来处理访问来源,Sentinel保护的资源如果被访问,就会调用 RequestOriginParser解析访问来源。
所以我们可以实现这个接口来自定义要控制的属性。例如对访问的IP进行限制;
@Component
public class CustomerOriginParser implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest request) {
//返回ip属性
return request.getRemoteAddr();
}
}
然后新增授权规则,配置限制的ip
然后浏览器访问 http://127.0.0.1:8401/testB,结果如下。
修改规则为白名单,则只有127.0.0.1可以访问,其它ip访问不了;
4.5 热点规则 (ParamFlowRule)
https://github.com/alibaba/Sentinel/wiki/%E7%83%AD%E7%82%B9%E5%8F%82%E6%95%B0%E9%99%90%E6%B5%81
4.5.1 概述
何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:
- 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
- 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制
热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
Sentinel 利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。热点参数限流支持集群模式。
4.5.2 热点参数规则
属性 | 说明 | 默认值 |
resource | 资源名,必填 | |
count | 限流阈值,必填 | |
grade | 限流模式 | QPS 模式 |
durationInSec | 统计窗口时间长度(单位为秒),1.6.0 版本开始支持 | 1s |
controlBehavior | 流控效果(支持快速失败和匀速排队模式),1.6.0 版本开始支持 | 快速失败 |
maxQueueingTimeMs | 最大排队等待时长(仅在匀速排队模式生效),1.6.0 版本开始支持 | 0ms |
paramIdx | 热点参数的索引,必填,对应 SphU.entry(xxx, args) 中的参数索引位置 | |
paramFlowItemList | 参数例外项,可以针对指定的参数值单独设置限流阈值,不受前面 count 阈值的限制。仅支持基本类型和字符串类型 | |
clusterMode | 是否是集群参数流控规则 | false |
clusterConfig | 集群流控相关配置 |
进一步解释
- 参数索引 : 代表@SentinelResource注解的方法参数,0代表第一个参数,1代表第二个参数。
- 统计窗口时长:默认1s,即1s内QPS达到阈值就进行限流。
- 参数例外项: 针对参数的具体值进行配置限流;例如 第一个参数,当=5的时候,单独配个限流阈值;不受上面配置的单机阈值影响;
4.5.2 基础配置测试
-
新增测试方法
配置blockHandler方法用来自定义返回到页面的报错提示;否则会直接报错,不友好。
@GetMapping("/testParamHot") @SentinelResource(value = "testParamHot",blockHandler = "blockHandler_ParamHot") public String testParamHot(Integer param1, Integer param2) { return "------testParamHot"; } public String blockHandler_ParamHot(Integer param1, Integer param2, BlockException e){ System.out.println("e"+e); return "------blockHandler_ParamHot"; }
-
sentinel配置规则如下
10s内,只要携带第一个参数即param1的url,QPS > 1则限流
-
浏览器快速访问 http://localhost:8401/testParamHot?param1=1
如下图,限流成功
4.5.3 参数例外项测试
参数例外项仅支持8中基础数据类型(包括对应的封装类型),配置时一定要对应上,否则不生效。
修改上面的规则,新增参数例外项如下图:
当param1 = 5的时候,限流阈值为100
浏览器快速访问 http://localhost:8401/testParamHot?param1=5
发现手动点很快也不限流了;说明走了下面的规则
5. @SentinelResource注解
https://github.com/alibaba/Sentinel/wiki/%E6%B3%A8%E8%A7%A3%E6%94%AF%E6%8C%81
注意:注解方式埋点不支持 private 方法。
@SentinelResource
用于定义资源,并提供可选的异常处理和 fallback 配置项。 @SentinelResource
注解包含以下属性:
value
:资源名称,必需项(不能为空)entryType
:entry 类型,可选项(默认为EntryType.OUT
)blockHandler
/blockHandlerClass
:blockHandler
对应处理BlockException
的函数名称,可选项。blockHandler 函数访问范围需要是public
,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为BlockException
。blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定blockHandlerClass
为对应的类的Class
对象,注意对应的函数必需为 static 函数,否则无法解析。fallback
/fallbackClass
:fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常(除了exceptionsToIgnore
里面排除掉的异常类型)进行处理。fallback 函数签名和位置要求:- 返回值类型必须与原函数返回值类型一致;
- 方法参数列表需要和原函数一致,或者可以额外多一个
Throwable
类型的参数用于接收对应的异常。 - fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定
fallbackClass
为对应的类的Class
对象,注意对应的函数必需为 static 函数,否则无法解析。
defaultFallback
(since 1.6.0):默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑(即可以用于很多服务或方法)。默认 fallback 函数可以针对所有类型的异常(除了exceptionsToIgnore
里面排除掉的异常类型)进行处理。若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。defaultFallback 函数签名要求:- 返回值类型必须与原函数返回值类型一致;
- 方法参数列表需要为空,或者可以额外多一个
Throwable
类型的参数用于接收对应的异常。 - defaultFallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定
fallbackClass
为对应的类的Class
对象,注意对应的函数必需为 static 函数,否则无法解析。
exceptionsToIgnore
(since 1.6.0):用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。
1.8.0 版本开始,defaultFallback
支持在类级别进行配置。
注:1.6.0 之前的版本 fallback 函数只针对降级异常(
DegradeException
)进行处理,不能针对业务异常进行处理。
特别地,若 blockHandler 和 fallback 都进行了配置,则被限流降级而抛出 BlockException
时只会进入 blockHandler
处理逻辑。若未配置 blockHandler
、fallback
和 defaultFallback
,则被限流降级时会将 BlockException
直接抛出(若方法本身未定义 throws BlockException 则会被 JVM 包装一层 UndeclaredThrowableException
)。
总结: blockHandler 是限流处理, fallback是熔断降级
6. 服务熔断功能
https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel 各种主流框架的支持
6.1 Sentinel整合Ribbon
-
pom引入依赖
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-sentinel</artifactId> </dependency>
-
然后方法上增加注解就行 @SentinelResource
@GetMapping(value = "/consumer/payment/nacos/{id}") @SentinelResource(fallback = "handleBlock") public String paymentInfo(@PathVariable("id") Long id) { int i= 1/0; return restTemplate.getForObject(serverURL+"/payment/nacos/"+id,String.class); } /** * 报错 降级处理方法 * @param id * @return */ public String handleBlock(@PathVariable("id") Long id) { return "服务维护中"+id; }
6.2 Sentinel整合Feign
https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel#feign-%E6%94%AF%E6%8C%81
在Feign的基础上,增加以下
-
配置文件打开 Sentinel 对 Feign 的支持
feign: sentinel: enabled: true
-
@FeignClient注解增加 fallback
用法和Hystrix一模一样,可以参考下 @HystrixCommand ( 文章: https://blog.csdn.net/shuai8624/article/details/109557105)
@FeignClient(name = "service-provider", fallback = EchoServiceFallback.class)
6.3 熔断框架比较
Sentinel | Hystrix | resilience4j | |
---|---|---|---|
隔离策略 | 信号量隔离(并发线程数限流) | 线程池隔离/信号量隔离 | 信号量隔离 |
熔断降级策略 | 基于时间响应、异常比率、异常数 | 基于异常比率 | 基于异常比率、响应时间 |
实时统计实现 | 滑动窗口(LeapArray) | 滑动窗口(基于RxJava) | Ring Bit Buffer |
动态规则配置 | 支持多种数据源 | 支持多种数据源 | 有限支持 |
扩展性 | 多个扩展点 | 插件形式 | 接口形式 |
基于注解的支持 | 支持 | 支持 | 支持 |
限流 | 基于QPS、支持基于调用关系的限流 | 有限的支持 | Rate Limiter |
流量整形 | 支持预热模式、匀速器模式、预热排队模式 | 不支持 | 简单的Rate Limiter模式 |
系统自适应保护 | 支持 | 不支持 | 不支持 |
控制台 | 提供开箱即用的控制台,可配置规则、查看秒级监控、机器发现等 | 简单的监控查看 | 不提供控制台,可对接其它监控系统 |
ps: Sentinel真香啊
7. 规则持久化
动态规则
https://github.com/alibaba/Sentinel/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%99%E6%89%A9%E5%B1%95
经过上面的练习,发现一个问题:
一旦重启应用,Sentinel配置的规则就没了,因此我们需要持久化。参考官网,可以持久化到nacos、zookeeper、Apollo、Redis等
本文 以Nacos为例。
修改项目 cloudalibaba-sentinel-service8401
-
引入pom依赖
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> </dependency>
-
修改application.yml配置,增加nacos数据源
server: port: 8401 spring: application: name: sentinel-service cloud: sentinel: transport: dashboard: 192.168.1.20:8080 # sentinel控制台地址 port: 8719 #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口 datasource: ds1: nacos: # nacos数据源配置 server-addr: 127.0.0.1:8848 dataId: sentinel-service data-type: json rule-type: flow
-
nacos添加配置
[{ "resource": "/testA", "limitApp": "default", "grade": 1, "count": 1, "strategy": 0, "controlBehavior": 0, "clusterMode": false }]
内容解析:
-
测试
- 重启项目后,查看sentinel规则
- 快速访问接口,查看规则是否生效