一文说透Sentinel熔断策略、降级规则、流量控制
2 Sentinel 限流熔断降级
Sentinel 可以简单的分为 Sentinel 核心库和 Dashboard。核心库不依赖 Dashboard,但是结合 Dashboard 可以取得最好的效果。我们先来学习Sentinel 核心库的使用,后面再学习Dashboard使用。
在我们项目中,用户请求通过hailtaxi-gateway
路由到hailtaxi-driver
或者hailtaxi-order
,还有可能在hailtaxi-order
中使用feign调用hailtaxi-driver
,所以我们有可能在单个服务中实现熔断限流,也有可能要集成feign调用实现熔断限流,还有可能在微服务网关中实现熔断限流。我们接下来一步一步实现每一种熔断限流操作。
SpringBoot集成:
如果在SpringBoot项目中使用Sentinel,首先需要引入spring-cloud-starter-alibaba-sentinel
依赖,并使用@SentinelResource
标识资源。
在hailtaxi-driver
工程中引入spring-cloud-starter-alibaba-sentinel
依赖,依赖如下:
<!--sentinel-->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId><version>2.2.5.RELEASE</version>
</dependency>
2.1 @SentinelResource定义资源
@SentinelResource
用于定义资源,并提供可选的异常处理和 fallback 配置项。 @SentinelResource
注解包含以下属性:
value | 资源名称,必需项(不能为空) |
---|---|
blockHandler / blockHandlerClass |
blockHandler 对应处理 BlockException 的函数名称,可选项。 ♞ blockHandler 函数访问范围需要是 public; ♞ 返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException。 ♞ blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。 |
fallback / fallbackClass |
fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。fallback 函数签名和位置要求: ♞ 返回值类型必须与原函数返回值类型一致; ♞ 方法参数列表需要和原函数一致,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。 ♞ fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。 |
defaultFallback(1.6.0 开始) |
默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑(即可以用于很多服务或方法)。默认 fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。defaultFallback 函数签名要求: ♞ 返回值类型必须与原函数返回值类型一致; ♞ 方法参数列表需要为空,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。 ♞ defaultFallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。 |
exceptionsToIgnore(1.6.0 开始) | 用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。 |
entryType | entry 类型,可选项(默认为 EntryType.OUT) |
blockHandler/blockHandlerClass
在hailtaxi-driver
中找到DriverController
中的info
方法,用户在打车的时候,会查询司机信息,如果司机不存在,此时会报错,代码改造如下:
/***** 司机信息*/
@GetMapping(value = "/info/{id}")
//@RequestMapping(value = "/info/{id}")
public Driver info(@PathVariable(value = "id")String id,HttpServletRequest request){log.info("当前服务占用的端口为:{}",port);Driver driver = driverService.findById(id);if (driver==null) {throw new RuntimeException("司机id="+id+"不存在");}return driver;
}
如果此时访问:http://localhost:18081/driver/info/3 查询司机信息,如果没有ID为3的司机信息,会报如下错误,
这种体验非常差,我们可以集成Sentinel使用@SentinelResource
的blockHandler
返回默认错误信息,形成降级!!!
1、Sentinel 支持在程序中抛出它定义的BlockException
异常,该异常会被Sentinel捕获,然后走降级方法,
为info()
方法添加一个@SentinelResource
注解,用来标注资源,表示当前方法需要执行限流、降级,在注解中添加value属性,用来标注资源,说白了就是给当前资源起个名字,blockHandler用来表示当前方法发生BlockException
异常的时候,将处理流程交给指定的方法blockExHandler()
处理,此时blockExHandler()
方法必须和抛出异常的方法在同一个类中,这是一种降级操作,代码如下:
/***** 司机信息*/
@SentinelResource(value = "info",blockHandler = "blockExHandler")
@RequestMapping(value = "/info/{id}")
public Driver info(@PathVariable(value = "id")String id) throws BlockException {log.info("当前服务占用的端口为:{}",port);Driver driver = driverService.findById(id);if (driver==null) {//throw new RuntimeException("司机id="+id+"不存在");throw new SystemBlockException("info", "司机id="+id+"不存在",null); // 抛出BlockException}return driver;
}/*** info资源出现BlockException后的降级处理*/
public Driver blockExHandler(String id,BlockException e) {Driver driver = new Driver();driver.setId(id);driver.setName("系统繁忙,稍后再试");return driver;
}
注意:
如果blockHandler方法和资源方法不在同一个类中,我们可以在
@SentinelResource
中添加blockHandlerClass
属性,指定降级处理类的方法所在的类,且要求blockHandler方法是静态的,代码如下:@SentinelResource(value = "info",blockHandler = "blockExHandler",blockHandlerClass = "xxx.xxx.Xxxx")
2、启动测试,访问:http://localhost:18081/driver/info/3 测试出错效果如下:
fallback/fallbackClass
1、如果我们希望抛出任何异常都能处理,都能调用默认处理方法,而并非只是BlockException
异常才调用,此时可以使用@SentinelResource
的fallback
属性,代码如下:
/***** 司机信息*/
@SentinelResource(value = "info"/*,blockHandler = "blockExHandler"*/,fallback = "exHandler")
@RequestMapping(value = "/info/{id}")
public Driver info(@PathVariable(value = "id")String id) throws BlockException {log.info("当前服务占用的端口为:{}",port);Driver driver = driverService.findById(id);if (driver==null) {throw new RuntimeException("司机id="+id+"不存在");// throw new SystemBlockException("info", "司机id="+id+"不存在",null); // 抛出BlockException}return driver;
}
/*** info资源出现任何类型异常后的降级处理* 方法参数可以添加一个Throwable 类型的参数,也可不添加*/
public Driver exHandler(String id,Throwable e) {Driver driver = new Driver();driver.setId(id);driver.setName("系统繁忙,稍后再试");return driver;
}
注意:
如果fallback方法和当前的资源方法不在同一个类中,可以使用
@SentinelResource
注解的fallbackClass
实现,也要求fallback方法是静态的,代码如下:@SentinelResource(value = "info",fallback ="exHandler" ,fallbackClass = "xx.xxx.xxx.xx.Xxx")
2、访问 http://localhost:18081/driver/info/3 测试出错效果如下:
defaultFallback
上面无论是blockHandler
还是fallback
,每个方法发生异常,都要为方法独立创建一个处理异常的方法,效率非常低,我们可以使用@SentinelResource
注解的defaultFallback
属性,为一个类指定一个全局的处理错误的方法,代码如下:
@RestController
@RequestMapping(value = "/driver")
@Slf4j
@RefreshScope
@SentinelResource(defaultFallback = "defaultExHandler")
public class DriverController {@Autowiredprivate DriverService driverService;public Driver defaultExHandler(Throwable e) {Driver driver = new Driver();driver.setName("系统繁忙,稍后再试");return driver;}/***** 司机信息*///@SentinelResource(value = "info"/*,blockHandler = "blockExHandler"*/,fallback = "exHandler")@SentinelResource("info")@RequestMapping(value = "/info/{id}")public Driver info(@PathVariable(value = "id")String id) throws BlockException {log.info("当前服务占用的端口为:{}",port);Driver driver = driverService.findById(id);if (driver==null) {throw new RuntimeException("司机id="+id+"不存在");// throw new SystemBlockException("info", "司机id="+id+"不存在",null); // 抛出BlockException}return driver;}
访问 http://localhost:18081/driver/info/3 效果如下:
2.2 Sentinel的规则
Sentinel 的所有规则都可以在内存态中动态地查询及修改,修改之后立即生效。同时 Sentinel 也提供相关 API,供您来定制自己的规则策略。
Sentinel 支持以下几种规则:流量控制规则、熔断降级规则、系统保护规则、来源访问控制规则 和 热点参数规则。
2.2.1 流量控制规则 (FlowRule)
流量规则的定义,重要属性如下:
Field | 说明 | 默认值 |
---|---|---|
resource | 资源名,资源名是限流规则的作用对象 | |
count | 限流阈值 | |
grade | 限流阈值类型,QPS 模式(1)或并发线程数模式(0) | QPS 模式 |
limitApp | 流控针对的调用来源 |
default ,代表不区分调用来源
|
strategy | 调用关系限流策略:直接、链路、关联 | 根据资源本身(直接) |
controlBehavior | 流控效果(直接拒绝/WarmUp/匀速+排队等待),不支持按调用关系限流 | 直接拒绝 |
clusterMode | 是否集群限流 | 否 |
同一个资源可以同时有多个限流规则,检查规则时会依次检查
strategy限流策略说明:
直接:资源达到限流条件时,直接限流。关联:A资源关联B资源,当关联的B资源达到阈值限流时,A资源也会被限流。链路:对于某资源C,有两个入口,从资源A->C,从资源B->C, 通过指定入口资源可以达到只记录从该入口进来的流量(指定资源从入口资源进来的流量,如果达到阈值,就可以对其限流)。
controlBehavior流控说明:
直接拒绝:请求直接失败。 WarmUp:当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。 排队等待:排队处理请求。
理解上面规则的定义之后,我们可以通过调用 FlowRuleManager.loadRules()
方法来用硬编码的方式定义流量控制规则。
QPS流量控制
1、我们先实现基于QPS流量控制,在hailtaxi-driver
的DriverApplication
启动类上添加如下方法加载限流规则,当DriverApplication
初始化完成之后加载规则,代码如下:
/**** 初始化规则*/
@PostConstruct
private void initFlowRule() {//规则集合List<FlowRule> rules = new ArrayList<FlowRule>();//定义一个规则FlowRule rule = new FlowRule("info");// 设置阈值rule.setCount(2);//设置限流阈值类型rule.setGrade(RuleConstant.FLOW_GRADE_QPS);//default,代表不区分调用来源rule.setLimitApp("default");//设置流控效果rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT);//将定义的规则添加到集合中rules.add(rule);//加载规则FlowRuleManager.loadRules(rules);
}
2、访问 http://localhost:18081/driver/info/1 此时不会抛出异常,但是频繁刷新,则会调用降级方法,效果如下:
线程数流量控制
1、我们修改限流阈值类型,代码如下:
@PostConstruct
public void initFlowRule() {//规则集合List<FlowRule> rules = new ArrayList<>();// 定义一个规则FlowRule rule = new FlowRule("info");// 设置基流量控制 的类型rule.setGrade(RuleConstant.FLOW_GRADE_THREAD);//默认是qps//设置流量阈值rule.setCount(2);// 将 规则添加到 集合中rules.add(rule);// 加载规则FlowRuleManager.loadRules(rules);
}
2、此时再来访问http://localhost:18081/driver/info/1
我们发现用浏览器无论怎么访问都不会出现降级现象,但是如果用Jmeter模拟多个线程,效果就不一样了,效果如下:
2.2.2 熔断降级规则 (DegradeRule)
熔断降级规则包含下面几个重要的属性:
Field | 说明 | 默认值 |
---|---|---|
resource | 资源名,即规则的作用对象 | |
grade | 熔断策略,支持慢调用比例/异常比例/异常数策略 | 慢调用比例 |
count | 慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值 | |
timeWindow | 熔断时长,单位为 s | |
minRequestAmount | 熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断(1.7.0 引入) | 5 |
statIntervalMs | 统计时长(单位为 ms),如 60*1000 代表分钟级(1.8.0 引入) | 1000 ms |
slowRatioThreshold | 慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入) |
同一个资源可以同时有多个降级规则。
理解上面规则的定义之后,我们可以通过调用 DegradeRuleManager.loadRules()
方法来用硬编码的方式定义熔断规则,
1、在DriverApplication
规则定义如下:
@PostConstruct
public void initDegradeRule() {List<DegradeRule> rules = new ArrayList<>();DegradeRule rule = new DegradeRule();// 设置资源名称rule.setResource("info");/*** 设置熔断策略* DEGRADE_GRADE_RT:平均响应时间* DEGRADE_GRADE_EXCEPTION_RATIO:异常比例数量* DEGRADE_GRADE_EXCEPTION_COUNT:异常数*/rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);//设置阈值rule.setCount(2);//设置 熔断时长rule.setTimeWindow(30);// 统计时长(单位为 ms) 默认1000rule.setStatIntervalMs(60*1000);//将规则添加到集合中rules.add(rule);DegradeRuleManager.loadRules(rules);
}
2、首先访问:http://localhost:18081/driver/info/1 ,确保没问题,
其次访问:http://localhost:18081/driver/info/3,多访问几次,造成熔断(5+2=7)
然后在访问:http://localhost:18081/driver/info/1,会发现已经有熔断降级效果了,
且查看服务控制台,发现不会有信息输出,表明已经熔断了,且从页面展示效果来看走了降级
等待30s后,再次访问:http://localhost:18081/driver/info/1,查看熔断是否结束!
2.2.3 系统保护规则 (SystemRule)
Sentinel 系统自适应限流从整体维度对应用入口流量进行控制,结合应用的 Load、CPU 使用率、总体平均 RT、入口 QPS 和并发线程数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
系统规则包含下面几个重要的属性:
Field | 说明 | 默认值 |
---|---|---|
highestSystemLoad |
load1 触发值,用于触发自适应控制阶段
|
-1 (不生效) |
avgRt | 所有入口流量的平均响应时间 | -1 (不生效) |
maxThread | 入口流量的最大并发数 | -1 (不生效) |
qps | 所有入口资源的 QPS | -1 (不生效) |
highestCpuUsage | 当前系统的 CPU 使用率(0.0-1.0) | -1 (不生效) |
理解上面规则的定义之后,我们可以通过调用 SystemRuleManager.loadRules()
方法来用硬编码的方式定义流量控制规则。
1、在hailtaxi-driver
的DriverApplication
中创建如下方法,代码如下:
/**** 系统自我保护*/
@PostConstruct
private void initSystemRule() {//系统自我保护集合List<SystemRule> rules = new ArrayList<>();//创建系统自我保护规则SystemRule rule = new SystemRule();//CPU使用率 值为[0,1],-1 (不生效)rule.setHighestCpuUsage(0.2);//所有入口资源的 QPS,-1 (不生效)rule.setQps(10);//入口流量的最大并发数,-1 (不生效)rule.setMaxThread(5);//所有入口流量的平均响应时间,单位:秒,-1 (不生效)rule.setAvgRt(5);//load1 触发值,用于触发自适应控制阶段,系统最高负载,建议取值 CPU cores * 2.5rule.setHighestSystemLoad(20);//将规则加入到集合rules.add(rule);SystemRuleManager.loadRules(rules);
}
我们可以测试CPU使用率自我保护,使用jmeter
测试如下:
2.2.4 访问控制规则 (AuthorityRule)
很多时候,我们需要根据调用方来限制资源是否通过,这时候可以使用 Sentinel 的访问控制(黑白名单)的功能。黑白名单根据资源的请求来源(origin
)限制资源是否通过,若配置白名单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。
授权规则,即黑白名单规则(AuthorityRule
)非常简单,主要有以下配置项:
resource
:资源名,即规则的作用对象limitApp
:对应的黑名单/白名单,不同 origin 用,
分隔,如appA,appB
strategy
:限制模式,AUTHORITY_WHITE
为白名单模式,AUTHORITY_BLACK
为黑名单模式,默认为白名单模式
了解了以上规则后,可以通过AuthorityRuleManager.loadRules
来加载规则
1、在hailtaxi-driver
的DriverApplication
中创建如下方法,代码如下:
@PostConstructpublic void initAuthorityRule() {AuthorityRule rule = new AuthorityRule();rule.setResource("info");rule.setStrategy(RuleConstant.AUTHORITY_WHITE);rule.setLimitApp("127.0.0.1,appB");AuthorityRuleManager.loadRules(Collections.singletonList(rule));}/*** Sentinel提供了 RequestOriginParser 接口来处理访问来源,Sentinel保护的资源如果被访问,* 就会调用 RequestOriginParser解析访问来源*/@Componentpublic class IpLimiter implements RequestOriginParser{@Overridepublic String parseOrigin(HttpServletRequest httpServletRequest) {return httpServletRequest.getRemoteAddr();}}
2、访问:http://localhost:18081/driver/info/1,不通过,走了降级
访问:http://127.0.0.1:18081/driver/info/1
2.2.4 热点规则 (ParamFlowRule)
何为热点?热点即经常访问的数据。
很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:
1:商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
2:用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制
热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
Sentinel 利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。热点参数限流支持集群模式。
要使用热点参数限流功能,需要引入以下依赖,将该依赖加入到hailtaxi-driver
中:
<!--热点参数限流-->
<dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-parameter-flow-control</artifactId><version>1.8.1</version>
</dependency>
然后为对应的资源配置热点参数限流规则,并在 entry
的时候传入相应的参数,即可使热点参数限流生效。
热点参数规则(ParamFlowRule
)类似于流量控制规则(FlowRule
):
属性 | 说明 | 默认值 |
---|---|---|
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 | 集群流控相关配置 |
我们可以通过 ParamFlowRuleManager
的 loadRules
方法更新热点参数规则
1、在DriverController
中创建一个司机筛选方法,比如根据城市来筛选,在DriverController
中创建一个方法:
/**** 搜素指定城市的司机*/
@SentinelResource(value = "search")
@GetMapping(value = "/search/{city}")
public Driver search(@PathVariable(value = "city")String city){System.out.println("查询的司机所在城市:"+city);//假设查询到了一个司机信息Driver driver = new Driver();driver.setName("唐僧老师");driver.setId("No.1");return driver;
}
2、对热门参数进行控制,对热点数据执行特殊限流,比如资源参数列表中的第一个参数值为恩施
的时候执行限流,在DriverApplication
中创建限流配置,代码如下:
/**** 热点参数初始化*/
@PostConstruct
private static void initParamFlowRules() {ParamFlowRule rule = new ParamFlowRule("search")//参数下标为0.setParamIdx(0)//限流模式为QPS.setGrade(RuleConstant.FLOW_GRADE_QPS)//统计窗口时间长度(单位为秒).setDurationInSec(10)//流控效果(支持快速失败和匀速排队模式)//CONTROL_BEHAVIOR_DEFAULT:限流行为,直接拒绝//CONTROL_BEHAVIOR_WARM_UP:限流行为,匀速排队//CONTROL_BEHAVIOR_RATE_LIMITER:限流行为,匀速排队.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT)//最大排队等待时长(仅在匀速排队模式生效 CONTROL_BEHAVIOR_RATE_LIMITER)//.setMaxQueueingTimeMs(600)//最大阈值为5.setCount(5);// 为特定参数单独设置规则//如下配置:当下标为0的参数值为恩施的时候,阈值到达2的时候则执行限流ParamFlowItem item = new ParamFlowItem()//参数类型为String类型.setClassType(String.class.getName())//设置阈值为2.setCount(2)//需要统计的值.setObject(String.valueOf("恩施"));rule.setParamFlowItemList(Collections.singletonList(item)); //返回的是不可变的集合,但是这个长度的集合只有1,可以减少内存空间//加载热点数据ParamFlowRuleManager.loadRules(Collections.singletonList(rule));
}
2、我们访问 http://localhost:18081/driver/search/天津/ 的时候,连续执行5次,才会限流,
我们访问 http://localhost:18081/driver/search/恩施/ 的时候,连续执行2次,就会限流,
2.3 OpenFeign支持
Sentinel 适配了 Feign 组件。如果想使用,除了外还需要 2 个步骤:
1:引入 `spring-cloud-starter-alibaba-sentinel` 的依赖
2:加入 spring-cloud-starter-openfeign 依赖
3:配置文件打开 Sentinel 对 Feign 的支持:feign.sentinel.enabled=true
在上面案例中,我们可以实现用户打车成功调用hailtaxi-order
执行下单,并且通过feign调用hailtaxi-driver
修改司机状态,此时我们可以使用Sentinel实现Feign调用降级、限流。
注意:
在进行操作之前,可以先将
hailtaxi-driver
中的访问控制规则注释掉,注释掉DriverApplication#initAuthorityRule
,DriverApplication#initSystemRule
上的注解即可
1、在hailtaxi-order
中引入sentinel
和OpenFeign
依赖,配置如下:
<!--sentinel-->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId><version>2.2.5.RELEASE</version>
</dependency><!--Openfeign api模块中已存在也可不引入-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2、在hailtaxi-order
的配置文件中开启Feign支持sentinel
,配置如下:
feign:#开启Sentinel对Feign的支持sentinel:enabled: true
注意:现在配置信息都存放在了
nacos
中,所以找到hailtaxi-order.yaml
的Data ID配置,将以上配置添加进去!注意修改完后一定要发布才能生效!!!
3、因为hailtaxi-order
要通过openfeign
去调用hailtaxi-driver
中的DriverController#status
方法,改造一下该方法
/***** 更新司机信息*/
@PutMapping(value = "/status/{id}/{status}")
public Driver status(@PathVariable(value = "id")String id,@PathVariable(value = "status")Integer status) throws Exception {log.info("当前服务占用的端口为:{}",port);//修改状态driverService.update(id,status);//修改状态后的司机信息Driver driver = driverService.findById(id);if (driver == null) {throw new RuntimeException("学生id="+id+",不存在");}return driver;
}
模拟被调用服务出现异常的情况
3、先验证正确性,启动hailtaxi-gateway
,hailtaxi-order
,hailtaxi-driver
服务,使用postman访问:
http://localhost:8001/order
4、为了测试程序异常能实现降级操作,我们在hailtaxi-order
中将OrderInfoController.add()
方法的司机ID改成一个不存在的司机ID,让程序报错,测试降级处理,代码如下:
/**** 下单*/
@PostMapping
public OrderInfo add(){//修改司机信息 司机ID=1Driver driver = driverFeign.status("3",2);// 改成一个不存在的id//创建订单OrderInfo orderInfo = new OrderInfo("No"+((int)(Math.random()*10000)), (int)(Math.random()*100), new Date(), "深圳北站", "罗湖港", driver);orderInfoService.add(orderInfo);return orderInfo;
}
5、再次启动测试:
注意:服务调用出错要进行降级操作有两个地方都可以进行,一是在被调用方进行降级,一是在调用方进行降级,
在被调用方进行降级前面已经讲过了,所以接下来讲解如何在调用方(openfeign)结合 sentinel 进行降级处理。
2.3.1 fallback
在hailtaxi-api
模块中找到DriverFeign
接口:
1、为Feign接口创建一个实现类:com.itheima.driver.feign.fallback.DriverFeignFallback
,在实现类中处理程序异常降级处理方法,代码如下:
package com.itheima.driver.feign.fallback;import com.itheima.driver.feign.DriverFeign;
import com.itheima.driver.model.Driver;
import org.springframework.stereotype.Component;@Component
public class DriverFeignFallback implements DriverFeign {/*** status()降级处理方法*/@Overridepublic Driver status(String id, Integer status) {Driver driver = new Driver();driver.setId(id);driver.setStatus(status);driver.setName("系统比较繁忙,请您稍后再试!");return driver;}
}
2、在DriverFeign
接口上添加fallback
属性指定降级处理的类,代码如下:
@FeignClient(value = "hailtaxi-driver",fallback = DriverFeignFallback.class)
注意:修改了
hailtaxi-api
模块,最好clean
,package
!!
3、启动运行,会发生如下问题:
java.lang.AbstractMethodError: com.alibaba.cloud.sentinel.feign.SentinelContractHolder.parseAndValidatateMetadata(Ljava/lang/Class;)Ljava/util/List;
出现上面问题的主要原因是当前SpringCloud版本存在问题。
Hoxton.SR1
中,fegin.context
接口方法的定义为parseAndValidatateMetadata
Hoxton.SR3
中,fegin.context
接口方法的定义为parseAndValidateMetadata
我们现在需要把Hoxton.SR1
换成Hoxton.SR3
,因此需要在hailtaxi-parent
修改SpringCloud版本:
将SpringCloud
版本升级至Hoxton.SR3
同时将SpringBoot
版本升级至2.2.10
,如上图:
https://github.com/spring-cloud/spring-cloud-release/wiki/Spring-Cloud-Hoxton-Release-Notes
此时我们测试,效果如下:
2.3.2 fallbackFactory
我们可以为DriverFeign
接口创建一个降级处理的工厂对象,在工厂对象中处理程序异常降级处理方法,用工厂对象处理可以拿到异常信息,代码如下:
1、创建:com.itheima.driver.feign.fallback.DriverFeignFallbackFactory
package com.itheima.driver.feign.fallback;import com.itheima.driver.feign.DriverFeign;
import com.itheima.driver.model.Driver;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;@Component
public class DriverFeignFallbackFactory implements FallbackFactory<DriverFeign> {@Overridepublic DriverFeign create(Throwable throwable) {return new DriverFeign() {/*** status()降级处理方法*/@Overridepublic Driver status(String id, Integer status) {Driver driver = new Driver();driver.setId(id);driver.setStatus(status);driver.setName("系统比较繁忙,请您稍后再试!");return driver;}};}
}
2、在DriverFeign
接口上添加fallbackFactory
属性指定讲解处理的类,代码如下:
@FeignClient(value = "hailtaxi-driver",fallbackFactory = DriverFeignFallbackFactory.class)
3、再次启动测试,效果如下:
好了,接下来,咱么来说一说Sentinel控制台
4 Sentinel控制台
Sentinel 控制台是流量控制、熔断降级规则统一配置和管理的入口,它为用户提供了机器自发现、簇点链路自发现、监控、规则配置等功能。在 Sentinel 控制台上,我们可以配置规则并实时查看流量控制效果。
4.1 Sentinel控制台安装
Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能。
Sentinel 控制台包含如下功能:
- 查看机器列表以及健康情况:收集 Sentinel 客户端发送的心跳包,用于判断机器是否在线。
- 监控 (单机和集群聚合):通过 Sentinel 客户端暴露的监控 API,定期拉取并且聚合应用监控信息,最终可以实现秒级的实时监控。
- 规则管理和推送:统一管理推送规则。
- 鉴权:生产环境中鉴权非常重要。这里每个开发者需要根据自己的实际情况进行定制。
Sentinel控制台安装可以基于jar包启动的方式安装,也可以基于docker安装,为了方便操作,我们这里采用docker安装方式:
docker run --name=sentinel-dashboard -d -p 8858:8858 -d --restart=on-failure bladex/sentinel-dashboard:1.8.0
安装好了后,我们可以直接访问 http://192.168.200.129:8858/,默认用户名和密码都是 sentinel
登录后,效果如下:
4.2 接入控制台
客户端需要引入 Transport 模块来与 Sentinel 控制台进行通信,可以通过
pom.xml
引入 JAR 包:<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-transport-simple-http</artifactId> <version>x.y.z</version> </dependency>
如果是SpringBoot工程接入Sentinel,可以直接引入如下依赖包:
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> <version>2.2.5.RELEASE</version> </dependency>
hailtaxi-gateway接入控制台:
1、引入依赖包:
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId><version>2.2.5.RELEASE</version>
</dependency>
2、在核心配置文件中配置Sentinel控制台服务地址
spring:cloud:sentinel:transport:port: 8719dashboard: 192.168.200.129:8858
注意:
1、这里的
spring.cloud.sentinel.transport.port
端口配置会在应用对应的机器上启动一个 Http Server,该 Server 会与 Sentinel 控制台做交互,比如限流规则拉取。2、配置信息现在是存储到nacos中,故要在nacos中找到
hailtaxi-gateway.yaml
,进行如下配置修改之后记得发布!
3、启动各个服务,
此时我们出发一些请求操作,再看Sentinel控制台会多一个服务监控:
4.3 可视化管理
4.3.1 实时监控
同一个服务下的所有机器的簇点信息会被汇总,并且秒级地展示在"实时监控"下。
注意: 实时监控仅存储 5 分钟以内的数据,如果需要持久化,需要通过调用实时监控接口来定制。
如果要获取监控数据,直接调用 http://localhost:8719/clusterNode 即可获取,效果如下:
4.3.2 流控规则
我们可以在【流控规则】页面中新增,点击【流控规则】进入页面新增页面,如下图:
资源名:其实可以和请求路径保持一致,这里的流控模式为QPS,触发流控执行阈值为1,流控模式为让当前请求的资源快速直白。
这里的参数和我们程序中的参数其实是一样的,如下说明:
resource:资源名,即限流规则的作用对象 count: 限流阈值 grade: 限流阈值类型(QPS 或并发线程数) limitApp: 流控针对的调用来源,若为 default 则不区分调用来源 strategy: 调用关系限流策略:直接,关联,链路 controlBehavior: 流量控制效果(直接拒绝、Warm Up、匀速排队)
我们测试效果如下:
4.3.3 降级规则
我们可以选择降级规则>新增降级规则
,如下图:
降级规则的熔断策略有3种,分别是慢调用比例、异常比例、异常数,和程序中是一样的。
4.3.4 热点数据
热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。
拓展知识点:
注意:如果流控模式是链路模式,需要引入如下依赖:
<dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-web-servlet</artifactId><version>1.8.0</version>
</dependency>
创建过滤器:
/**** CommonFilter过滤器* @return*/
@Bean
public FilterRegistrationBean sentinelFilterRegistration() {FilterRegistrationBean registration = new FilterRegistrationBean();registration.setFilter(new CommonFilter());registration.addUrlPatterns("/*"); //过滤所有请求// 入口资源关闭聚合registration.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "false");registration.setName("sentinelFilter");registration.setOrder(1);return registration;
}
bootstrap.yml配置:web-context-unify: false
cloud:sentinel:transport:port: 8719dashboard: localhost:8858web-context-unify: false #可根据不同的URL 进行链路限流
本文由传智教育博学谷 - 狂野架构师教研团队发布 转载请注明出处!
一文说透Sentinel熔断策略、降级规则、流量控制相关推荐
- sentinel 控制台讲解-降级规则-降级策略:RT
上图表示 需要1秒持续进入至少5个请求,并且 程序的平均响应时间大于 设定的阈值,就会触发降级,打开断路器,等时间窗口结束(秒),就会关闭降级 注意 Sentinel 默认统计的 RT 上限是 490 ...
- sentinel 熔断降级
sentinel 熔断降级 官网:https://sentinelguard.io/zh-cn/docs/circuit-breaking.html 熔断降级 熔断降级:服务由于响应慢.异常等原因触发 ...
- 服务熔断与降级(Sentinel)
文章目录 1.概述 ①.什么是Sentinel ②.Windows下载安装 ③.Docker安装 2.工程案例 ①.建Module ②.POM ③.YML ④.主启动 ⑤.业务类 ⑥.测试 3.流控规 ...
- Alibaba Sentinel DegradeRule 降级规则源码
降级方式 Alibaba Sentinel 支持多种降级方式: 根据响应时间:判断单位时间内平均响应时间是否达到阈值: 根据异常比例:判断单位时间内,异常数量和异常比例是否达到阈值: 根据异常数量:判 ...
- 【原理/Sentinel】RT降级策略原理
文章目录 1 前言 2 测试过程 3 过程分析 4 源码简单分析 1 前言 在1.8.0之前的版本中,Sentinel的降级策略可以选择RT,也就是平均响应时间的降级策略.从网上也能了解到基本规则就是 ...
- Sentinel微服务限流、熔断、降级介绍(一)
概述 在互联网应用中,会有很多突发性的高并发访问场景,比如双11大促.秒杀等.这些场景最大的特点就是访问量会远远超出系统所能够处理的并发数. 在没有任何保护机制的情况下,如果所有的流量都进入服务器,很 ...
- SpringCloud Alibaba Sentinel 熔断降级 - 程序配制方式实现
一.Sentinel 上篇文章我们讲解了Sentinel 流控规则的配制,本篇文章我们继续讲下Sentinel 的熔断降级,依然采用程序配制方式实现. 上篇文章地址:https://blog.csdn ...
- Sentinel服务熔断和降级
还记得我们前所说的服务降级吗,也就是说我们需要在整个微服务调用链路出现问题的时候,及时对服务进行降级,以防止问题进一步恶化. 那么,各位是否有思考过,如果在某一时刻,服务B出现故障(可能就卡在那里了) ...
- sentinel限流_微服务架构进阶:Sentinel实现服务限流、熔断与降级
摘要 Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案,Sentinel 作为其核心组件之一,具有熔断与限流等一系列服务保护功能,本文将对其用法进行详细介绍. Senti ...
最新文章
- 别再被 Python 洗脑了!!
- python开发环境配置config_manjaro与python开发环境配置
- HDUOJ 1060 Leftmost Digit
- 【Linux】一步一步学Linux——more命令(39)
- 跟着别人的感觉做网络推广之二
- 11G Oracle RAC添加新表空间时数据文件误放置到本地文件系统的修正
- 智能指针的释放_看完这篇,别再说不会智能指针了
- python回测量化交易策略收益率
- CSS 加过渡效果transition
- 蚂蚁森林:国庆节前组织网友去阿拉善等三地参与秋季验收
- Synchronized的底层实现原理(看这篇就够了)
- 按照长度递减的方式打印 字符串 BackSpace
- EasyExcel导出excel(写)
- win10计算机设备感叹号,win10系统设备管理中摄像头驱动显示黄色感叹号的解决办法...
- 小学听力测试英语软件,你知道有哪些软件适合给小学生练习在线英语听力吗?...
- macOS禁用指定应用联网的方法
- padbineditor.php,《智龙迷城》padBinEditor修改器教学
- 《弃子长安》第六章 九煞夺命
- 计算机开不了机反复重启,电脑一直重启就是开不了机怎么样解决
- MIPI 系列之 D-PHY
热门文章
- inv如何用计算机计算,计算器INV是用那个键表示的
- 【软件工程】实验九 建立动态模型--自行车租赁管理系统
- 钉钉H5应用后台回调地址设置(服务端代码逻辑编写).NetCore API
- pygame设计舒尔特方格游戏python舒尔特方格小程序
- 钱文忠解读《弟子规》读后感
- 模拟赛 Jams倒酒
- 洛谷 P5520 青原樱(组合数学插板法 or 插空法 模板)
- 获取高德POI(关键词搜索法 多边形搜索法 周边搜索法)综合运用 2022新版高德poi下载
- 北京交通大学c语言作业,北京交通大学c语言综合程序设计(黄宇班).doc
- 电脑使用技巧 快捷键