四. Sentinel普通流控
1. 普通流控定义
/**
* flow 流控规则,详情查看RuleType
*/
FLOW("flow", FlowRule.class)
作用在网关的流控称之为网关流控,相对的作用在除网关之外的微服务流控这里称为普通流控
在上一个章节中,发现网关流控并不是万能的,像认证中心youlai-auth调用系统服务youlai-admin这种微服务相互调用而不走网关的情况,网关流控表示无能为力,但不可否认的是网关流控确实能够应对大多数场景的流控。
所以在像上文中的网关流控无能为力的案例,则需要普通流控的救场。
2. 普通流控的规则
Field 说明 默认值
resource 资源名,资源名是限流规则的作用对象
count 限流阈值
grade 限流阈值类型,QPS 【1】或线程数模式【0】 QPS 模式
limitApp 流控针对的调用来源 default,代表不区分调用来源
strategy 判断的根据是资源自身,还是根据其它关联资源 (refResource),还是根据链路入口 根据资源本身
controlBehavior 流控效果(直接拒绝 / 排队等待 / 慢启动模式) 直接拒绝
3. 导入依赖
com.alibaba.cloud
spring-cloud-starter-alibaba-sentinel
com.alibaba.csp
sentinel-datasource-nacos
4. 微服务配置
spring:
application:
name: youlai-admin
cloud:
nacos:
discovery:
server-addr: http://localhost:8848
config:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
file-extension: yaml
sentinel:
enabled: true
eager: true # 取消控制台懒加载,项目启动即连接Sentinel
transport:
client-ip: localhost
dashboard: localhost:8080
datasource:
# 限流规则,flow为key,随便定义
flow:
nacos:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
dataId: ${spring.application.name}-flow-rules
groupId: SENTINEL_GROUP
data-type: json
rule-type: flow
5. Nacos添加流控规则
进入Nacos控制台,添加规则配置文件,接着上文的案例,在认证的时候,youlai-auth需通过feign调用youlai-admin根据用户名获取用户信息。
进入Sentinel控制台查看,除了刚在Nacos添加的规则之外,还可以看到普通流控面板和网关流控面板的区别
6. 普通流控测试
经过网关流控限制只能有10条请求到youlai-auth,接下来youlai-auth调用youlai-admin链路中,因为限制了youlai-admin的QPS上限为5,所以最终应该是只有5条请求是有效的。看测试结果:
7. 自定义异常
上面被限流后的异常信息,显然不是想要的,那么如何自定义普通流控异常呢?
**解决方案:**实现BlockExceptionHandler接口
@Component
public class DefaultBlockExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
response.setStatus(HttpStatus.ok().status());
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charset=utf-8");
if(e instanceof FlowException){
// objectMapper.writeValue 用于将java对象转位JSON格式返回调用方
new ObjectMapper().writeValue(response.getWriter(), Result.failed(ResultCode.FLOW_LIMITING));
}
}
}
为了测试普通流控,首先关闭网关流控,排除一些异常干扰
添加获取当前登录用户信息的HTTP请求
因为此HTTP接口需要认证,所以需要在请求头添加token。鼠标右击HTTP请求->添加->配置元件->HTTP信息头管理
HTTP信息头管理器添加token
执行线程组,查看自定义异常生效
五. Sentinel熔断降级
1. 熔断降级概述
微服务架构都是分布式的,不同服务相互调用,组成复杂的调用链路。复杂的链路上某一环不稳定,就可能层层级联,最终导致整个链路都不可用。因此需要对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定的调用,避免局部不稳定因素导致正题的雪崩。熔断降级作为保护自身的手段,通常在客户端(调用端)进行配置。
2. 熔断策略
Sentinel提供了三种熔断策略:
慢调用比例: 请求响应时间大于设置的RT(即最大的响应时间)则统计为慢调用。触发此熔断策略的条件需要满足两个条件,一是单位统计时长(statIntervalMs)内请求数大于设置的最小请求数,二是慢调用的比例大于阈值,接下来在熔断时长的范围内请求会自动的被熔断。过了熔断时长后,熔断器进入探测恢复状态(HALF-OPEN状态),若接下来的一个请求响应时间小于设置的慢调用RT则结束熔断,若大于设置的慢调用RT则会再次被熔断。
异常比例:当单位统计时长请求数大于设置的最小请求数,并且异常的比例大于阈值,则接下来的熔断时长内请求会被自动熔断。
异常数:当单位统计时长内的异常数目超过阈值之后会自动进行熔断。
3. 熔断降级规则
熔断降级规则(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 引入)
4. 微服务配置
spring:
cloud:
sentinel:
# 降级规则,degrade为降级key,随便取名
degrade:
nacos:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
dataId: ${spring.application.name}-degrade-rules
groupId: SENTINEL_GROUP
data-type: json
rule-type: degrade
5. Nacos添加熔断降级规则
方便看到异常熔断的效果,选择了异常数的熔断策略,毕竟数数比计算比例简单多了。资源名为getCurrentUser是怎么回事,不急下文提到。总之这里的配置的大概意思就是说针对getCurrentUser资源,如果请求该接口出现了异常,则进行熔断,熔断时长为5秒。
6. 熔断异常模拟
先模拟一段在运行时发生异常的代码,在获取当前登录用户信息的接口埋个雷吧,注意到@SentinelResource注解中的value值getCurrentUser,也就是资源名称,联系上文,降级规则就是针对这个接口的方法。和上面在普通流控测试使用的是请求的路径不同,这里显示指定了资源名称和降级规则配置去做匹配。
@SentinelResource注解中的属性除了定义资源名的属性值value,还有两个属性有关降级处理分别是blockHandlerClass和blockHandler。意思是在单位时间接口异常数超过设置的阈值后进入熔断,在熔断时长(上面降级规则中设置的是5秒)范围内,再有请求过来访问该接口时,不会再走接口方法体内的逻辑。因为前面几次接口出现异常,那么敢断定接下来短时间内大概率还是会发生异常,所以索性就把后续的请求拦截避免,这也是熔断的意义。
在5秒的熔断时长内,如果再有请求访问该接口则会走降级的逻辑,也就是上图中指定的UserBlockHandler#handleGetCurrentUserBlock降级处理方法。
7. 熔断降级测试
在测试前,需要关闭网关那边流控,排除一些异常情况下的干扰。还有为了方便在JMeter查看结果,临时关闭全局异常处理器GlobalExceptionHandler。
还是拿上一节配置好的测试普通流控的线程组,获取登录用户的信息来作为熔断降级的测试案例,先看一下线程组的设置:
线程数为10,达到了熔断降级最小请求数(规则配置的5)的要求
获取登陆用户信息的接口信息
请求头添加token
测试线程组配置好之后看看使用不使用熔断降级和使用熔断降级的区别:
不使用熔断降级
配置中关闭Sentinel
sentinel:
enabled: false
1
2
发现了吗?这种请求异常处理模式头铁啊,即使撞了南墙也不会回头,下次继续撞,下下次继续撞。ok,你没关系,那你有考虑一直被你撞的墙(服务器)了没?
使用熔断降级
配置中开启Sentinel
sentinel:
enabled: true
1
2
通过日志可以看到进入主线代码的只有一次,后续的请求直接进入降级支线。
过了熔断时长5秒后,熔断器进入探测恢复状态(HALF-OPEN状态),这时候如果一个请求到主线没异常,关闭熔断器,让后续的请求都到主线过来;如果还是异常,打开熔断器。
六. Sentinel整合Feign熔断降级
1. Feign与Sentinel整合意义
在微服务架构中,声明式调用Feign在微服务之间调用充当重要的角色,在使用Feign的过程中如果为了系统的健壮性,一定会考虑如果因目标服务异常调用失败后的处理。
说到这里,相信对微服务有些了解的童鞋对下面的代码很熟悉:
上面两张图反应了Feign客户端在远程调用目标服务失败后,继而选择了降级的逻辑,像做人一样随时要给自己留一条后路,也就是稳,折射到程序亦是如此。这里只是一个降级的自定义异常返回,实际情况根据业务而定。
看到上面的代码,Feign在设计上就支持了降级的处理。这时候相信大家都会有一个疑问,Feign本身已经支持降级,那还需要Sentinel做什么?
换句话说可能会好理解一点,Sentinel给Feign带来了什么好处?
这个问题其实不难理解,先直接从字面上切入。
Feign是能够做到降级,Sentinel能够实现熔断降级,突显出来也就是熔断这一词,其中熔断的具体表象是怎样的?举个栗子说明:
假如客户端a通过feign调用b服务100次,此时b服务故障
没有熔断
a的第1次请求走到b服务跟前,看着b躺在地上没动静,响应给客户端a说b没动静,让客户端a自己看着办吧。后面如此往复99次,每次a都需要走到b的面前然后再响应给客户端a,并告知b故障了。
有熔断
a的第1次请求走到b服务跟前,看着b躺在地上没动静,这时候a就比较机智,判断b服务没有一时半刻是起不来了,就响应给客户端a并说这一时半刻钟的请求你自己看着处理吧,没有必要再到b面前,后面的99次请求就不会再到服务b那里了,省时省力。
想通过上面的举例说明熔断的意义和作用,因为Feign已经支持了降级,那再搭配上Sentinel的熔断,岂不是如虎添翼?
接下来将通过有来项目中的实例,认证中心【youlai-auth】在登录时需要远程feign调用系统服务【youlai-admin】的根据用户名获取用户信息的接口,来说明Sentinel如何整合Feign实现熔断降级及熔断降级的魅力。
2. 导入依赖
youlai-auth添加Sentinel和Nacos持久化规则依赖
com.alibaba.cloud
spring-cloud-starter-alibaba-sentinel
com.alibaba.csp
sentinel-datasource-nacos
3. 微服务配置
youlai-auth开启Feign对Sentinel的支持
spring:
application:
name: youlai-auth
cloud:
sentinel:
enabled: true
eager: true # 取消控制台懒加载,项目启动即连接Sentinel
transport:
client-ip: localhost
dashboard: localhost:8080
datasource:
# 降级规则
degrade:
nacos:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
dataId: ${spring.application.name}-degrade-rules
groupId: SENTINEL_GROUP
data-type: json
rule-type: degrade
# Feign开启对Sentinel支持
feign:
sentinel:
enabled: true
4. 熔断降级规则
在Nacos控制台添加youlai-auth的降级规则
[
{
"resource": "GET:http://youlai-admin/api.admin/v1/users/username/{username}",
"grade": 2,
"count": 1,
"timeWindow": 5
}
]
注意资源名称的生成规则,上面配置的意思是如果单位时间内出现了1次异常数,那没接下来5秒的时间窗口范围内的请求,因为熔断器打开,请求直接走降级逻辑。
5. 熔断降级测试
首先要模拟系统服务的根据用户名获取用户信息的接口异常,具体如下图:
配置JMeter线程组,单位时间1s内执行10个请求,具体配置在普通流控有说明,这里不做赘述。
/
结果在youlai-auth确实执行了10次请求,因为目标服务的异常走了降级的逻辑
但是真正进入youlai-admin的根据用户名获取用户信息的接口方法却只有1次,后续的9次请求直接走feign客户端的降级逻辑
上面的测试结果验证了Feign整合Sentinel之后实现了熔断和降级,至此Feign不再孤军奋战。
七. 结语
本文就Sentinel的流控、熔断降级从实战的角度去逐一验证。网关流控、普通流控能够在有限的资源能力保障系统的稳定运行,熔断降级能够在系统故障时提供兜底的处理逻辑保证系统的健壮性,支持降级的Feign整合Sentinel之后get到熔断的技能,至此熔断降级双剑合璧。
以前觉得微服务的限流、熔断降级是可有可无的存在,所以在开源项目中一直迟迟没有做相关的整合,当真正理解这其中的利害关系之后,微服务离不开这些。
当然本文提到的Sentinel功能的冰山一角,像限流延伸的还有热点key、IP限流、参数限流等等,具体选择使用根据场景,功能丰富,总会有你需要的。而且容易上手,是一个很不错的框架,内部的实现原理和还有算法很有必要去了解深入下。
如果有问题,欢迎加我微信(微信号:haoxianrui)
八. 附录
本文涉及的源码地址:
平台 地址
github https://github.com/hxrui/youlai-mall
gitee https://gitee.com/youlaitech/youlai-mall
文中的Sentinel规则配置已放置在项目document/nacos/SENTINEL_GROUP.zip,导入到Nacos控制台即可
当然你也可以本地启动Sentinel控制台,已经把官方的jar包放置在项目youlai-middleware/setinel/sentinel-dashboard-1.8.1.jar
cd youlai-middleware/setinel
java -jar sentinel-dashboard-1.8.1.jar
1
2
本地访问 http://localhost:8080即可进入Sentinel控制台