Sentinel 流量控制 & 服务熔断降级详解
Sentinel 流量控制 &服务熔断降级介绍
流量控制介绍
在这里我用景区的例子解释一下
一个旅游景点日接待游客数量为 8K,8K 以后的游客就无法买票进去景区。
对应编程来说就是,一个接口 QPS(每秒请求数)最大为 100,在 QPS100 之后的请求我们就要限制其访问,并给出友好提示。
不限制 QPS 无限的次数就会造成服务器的宕机。
服务熔断降级
在调用系统的时候,如果调用链路中的某个资源出现了不稳定,最终会导致请求发生堆积,进而导致级联错误
而熔断降级就可以解决这个问题,所谓的熔断降级就是当检测到调用链路中某个资源出现不稳定的表现,例如请求响应时间长或异常比例升高的时候,则对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联故障
sentinel 流量控制入门
创建本地应用
整体流程分析
创建 springBoot 项目
导入 sentinel 的坐标(此处使用为 gradle)
创建 Controller 测试接口,定义限流规则同时引用限流规则
导入核心依赖
本地 Sentinel 控制台
下载 sentinel 控制台 jar 包
下载地址
启动 Sentinel 控制台
启动 Sentinel 控制台需要 JDK 版本为 1.8 及以上版本。
使用一下命令启动
java -Dserver.port=端口号 -jar sentinel-dashboard-1.8.0.jar
访问控制台
通过浏览器访问 http://localhost:端口号即可访问控制台,默认用户名密码都是 sentinel
Sentinel 自定义资源方式
抛出异常的方式定义资源
返回布尔值方式定义资源
异步调用支持
注解方式定义资源
主流框架的默认适配
抛出异常的方式定义资源
Sentinel 中的 SphU 包含了 try-catch 风格的 API。用这种方式,当资源发生了限流之后会抛出 BlockException 。
这个时候就可以捕获异常,进行限流之后的逻辑操作,在入门案例中就是使用此方式实现的,关键代码:
特别地,若 entry 的时候传入了热点参数,那么 exit 的时候也一定要带上对应的参数(exit(count, args)),否则可能会有统计错误。这个时候不能使用 try-with-resources 的方式。另外通过 Tracer.trace(ex) 来统计异常信息时,由于 try-with-resources 语法中 catch 调用顺序的问题,会导致无法正确统计异常数,因此统计异常信息时也不能在 try-with-resources 的 catch 块中调用 Tracer.trace(ex)。
手动 exit 示例:
热点参数埋点示例:
SphU.entry() 的参数描述:
参数名
类型
解释
默认值
entryType
EntryType
资源调用的流量类型,是入口流量(EntryType.IN)还是出口流量(EntryType.OUT),注意系统规则只对 IN 生效
EntryType.OUT
count
int
本次资源调用请求的 token 数目
1
args
Object[]
传入的参数,用于热点参数限流
无
注意:SphU.entry(xxx) 需要与 entry.exit() 方法成对出现,匹配调用,否则会导致调用链记录异常,抛出 ErrorEntryFreeException 异常。常见的错误:
自定义埋点只调用 SphU.entry(),没有调用 entry.exit()
顺序错误,比如:entry1 -> entry2 -> exit1 -> exit2,应该为 entry1 -> entry2 -> exit2 -> exit1
返回布尔值方式定义资源
Sentinel 中的 SphO 包含了 if-else 风格的 API。用这种方式,当资源发生了限流之后会返回 false ,这时候可以根据返回值,进行限流之后的逻辑处理。
在项目中创建 TestBooleanController 中使用返回 booelan 的方式定义资源 view code
**在控制台进行流控规则的配置 **
注意 SphO.entry(xxx)需要与 SphO.exit()方法成对出现,匹配调用,位置正确,否则就会导致调用链记录异常,抛出 ErrorEntryFreeException 异常
异步调用支持
Sentinel 支持异步调用链路的统计。在异步调用中,需要通过 SphU.asyncEntry(xxx) 方法定义资源,并通常需要在异步的回调函数中调用 exit 方法。
启动类开启异步调用 @EnableAsync
开启方法的异步调用 @Async
SphU.asyncEntry(xxx) 不会影响当前(调用线程)的 Context,因此以下两个 entry 在调用链上是平级关系(处于同一层),而不是嵌套关系:
若在异步回调中需要嵌套其它的资源调用(无论是 entry 还是 asyncEntry),只需要借助 Sentinel 提供的上下文切换功能,在对应的地方通过 ContextUtil.runOnContext(context, f) 进行 Context 变换,将对应资源调用处的 Context 切换为生成的异步 Context,即可维持正确的调用链路关系。示例如下:
此时的调用链就类似于:
更详细的示例可以参考 Demo 中的 AsyncEntryDemo,里面包含了普通资源与异步资源之间的各种嵌套示例。
注解方式定义资源
Sentinel 支持通过 @SentinelResource 注解定义资源并配置 blockHandler 和 fallback 函数来进行限流之后的处理。使用 Sentinel Annotation AspectJ Extension 的时候需要引入以下依赖
implementation("com.alibaba.csp:sentinel-annotation-aspectj:1.7.2")
@SentinelResource 注解
注意:注解方式埋点不支持 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)。
示例:
从 1.4.0 版本开始,注解方式定义资源支持自动统计业务异常,无需手动调用 Tracer.trace(ex) 来记录业务异常。Sentinel 1.4.0 以前的版本需要自行调用 Tracer.trace(ex) 来记录业务异常。
配置
Spring Cloud Alibaba
若您是通过 Spring Cloud Alibaba 接入的 Sentinel,则无需额外进行配置即可使用 @SentinelResource 注解。
Spring AOP
若您的应用使用了 Spring AOP(无论是 Spring Boot 还是传统 Spring 应用),您需要通过配置的方式将 SentinelResourceAspect 注册为一个 Spring Bean:
我们提供了 Spring AOP 的示例,可以参见 sentinel-demo-annotation-spring-aop。
AspectJ
若您的应用直接使用了 AspectJ,那么您需要在 aop.xml 文件中引入对应的 Aspect:
主流框架的默认适配
文档地址:https://github.com/alibaba/Sentinel/wiki/主流框架的适配 #spring-cloud
规则的种类
Sentinel 的所有规则都可以在内存态中动态地查询及修改,修改之后立即生效。同时 Sentinel 也提供相关 API,供您来定制自己的规则策略。
Sentinel 支持以下几种规则:流量控制规则、熔断降级规则、系统保护规则、来源访问控制规则 和 热点参数规则。
流量控制规则 (FlowRule)
流量规则的定义
重要属性:
Field
说明
默认值
resource
资源名,资源名是限流规则的作用对象
count
限流阈值
grade
限流阈值类型,QPS 模式(1)或并发线程数模式(0)
QPS 模式
limitApp
流控针对的调用来源
default,代表不区分调用来源
strategy
调用关系限流策略:直接、链路、关联
根据资源本身(直接)
controlBehavior
流控效果(直接拒绝/WarmUp/匀速+排队等待),不支持按调用关系限流
直接拒绝
clusterMode
是否集群限流
否
同一个资源可以同时有多个限流规则,检查规则时会依次检查。
通过代码定义流量控制规则
理解上面规则的定义之后,我们可以通过调用 FlowRuleManager.loadRules() 方法来用硬编码的方式定义流量控制规则,比如:
原文链接:https://www.cnblogs.com/TJ21/p/14513123.html
如果觉得本文对你有帮助,可以关注一下我公众号,回复关键字【面试】即可得到一份 Java 核心知识点整理与一份面试大礼包!另有更多技术干货文章以及相关资料共享,大家一起学习进步!
版权声明: 本文为 InfoQ 作者【Java王路飞】的原创文章。
原文链接:【http://xie.infoq.cn/article/0338692ec2243c3ba08dbf642】。未经作者许可,禁止转载。
评论