常用于实现熔断降级的框架有Hystrix
、Sentinel
,我们常说的Spring Cloud
项目说的其实是Spring Cloud Netflix
,Hystrix
以及前面学习过的Ribbon
都是Netflix
系的家族成员,所以使用Hystrix
可以非常简单的与当前项目中使用到的OpenFeign
、Ribbon
整合,但笔者并没有选择Hystrix
,而是选择阿里系的Sentinel
。
为什么选择Sentinel
而不是Hystrix
?从接入简单考虑可能选择Hystrix
是不错的选择,但笔者对Hystrix
比较陌生,陌生到只听过名字。笔记在去年做的Dubbo
项目中使用过Sentinel
,所以对Sentinel
很熟悉,并且看过它的一点底层源码,例如,如何统计当前时间窗口的QPS
、计算并发使用的线程数等。所以笔者选择的是自己熟悉的。
Sentinel
与Hystrix
谁更好?由于不了解Hystrix
,所以这个问题笔者回答不了,但合适最重要,能够达到目的,并且不会消耗应用资源,不影响性就可以。并不是不愿意去学Hystrix
,只是觉得没有必要,学一个这种框架从入门到熟悉部分源码也就两三天时间。使用Sentinel
有一个好处,文档是中文的,使用文档介绍的也比较齐全,对入门较友好。
OpenFeign整合Sentinel实现熔断降级
按照惯性,本篇先介绍如何将Sentinel
与OpenFeign
整合使用,并且熔断降级策略使用动态配置,将配置存储在配置中心。
sck-demo
项目源码地址:sck-demo
(这是一个使用Spring Cloud Kubernetes
搭建的微服务demo
工程,可翻阅往期文章学习Spring Cloud Kubernetes
的使用以及源码分析)。
Sentinel
官方使用文档:https://github.com/alibaba/Sentinel/wiki/%E7%86%94%E6%96%AD%E9%99%8D%E7%BA%A7
借助spring-cloud-starter-alibaba-sentinel
实现与OpenFeign
整合,下一篇分析完源码之后,我们也可以自己实现一个spring-cloud-starter-kubernetes-sentinel
(滑稽)。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
引入该依赖也会将sentinel-core
以及sentinel-datasource-extension
引入,实际上实现熔断降级我们只需要这两个jar
包就够了,当然,前提是自己实现与OpenFeign
的整合。而spring-cloud-starter-alibaba-sentinel
提供了Sentinel
与OpenFeign
整合使用的实现。
熔断是在consumer
端实现的,所以在consumer
端的application.yaml
配置文件中添加如下配置。
feign:
sentinel:
enabled: true
通过继承AbstractDataSource
实现自定义数据源,降级规则以什么格式存储由你来定,由于sck-demo
项目使用Kubernetes
的ConfigMap
资源存储动态配置,所以笔者选择使用yaml
格式配置降级规则。
创建用于装载降级规则配置的Properties
类DegradeRuleProps
,代码如下。
自定义降级规则数据源DegradeRuleDataSource
实现代码如下。
动态数据源只是接口,实现了动态数据源并不意味着Sentinel
会帮你实现初始化加载或者更新降级规则。所以我们在Bean
的初始化方法中初始化加载一次降级规则,并实现ApplicationListener
接口监听RefreshScopeRefreshedEvent
动态配置刷新事件,当配置改变时,重新加载降级规则。
让降级规则生效只需要调用DegradeRuleManager
的loadRules
方法,让Sentinel
更新降级规则DegradeRule
。如果不配置任何降级规则,则不会对任何资源降级,但Sentinel
依然会统计每个资源的时间窗口数据。
编写自动配置类SentinelAutoConfiguration
,当feign.sentinel.enabled
开启时,也就是启动OpenFeign
整合Sentinel
的自动配置时,再将数据源注册到Spring
容器中。最好将数据源写在一个组件模块中,实现代码共用。
在resources
目录下创建一个META-INF
目录,添加spring.factories
文件,在文件中添加如下内容。
本地测试不使用配置中心,直接在application-[activeProfile].yaml
文件中添加降级规则,例如。
测试例子配置两个熔断降级规则,resource
资源名称配置格式为:(请求方式)+":"+资源url
。以资源POST:http://localhost:8080/v1/demo1
为例,该资源配置使用的降级规则为DEGRADE_GRADE_EXCEPTION_COUNT
(对于值为2
),总数为10
,时间窗口为1
秒,最新请求数5
。意思是,如果当前时间窗口内(1
秒内)调用资源的总数大于5
,并且出现异常总数大于10
时,接下来的请求将触发熔断,直到下个时间周期到来重新计算。
笔者去年抄过Sentinel
的时间窗口请求数据统计的源码,通过修改实现通用QPS
统计工具包qps-helper
,Github
下载地址:qps-helper
。感兴趣可以看下。
最后给接口上的@FeignClient
注解配置fallback
属性,配置降级处理。fallback
属性要求配置一个类,该类必须实现相同的接口。
ServiceDegradeFallback
类中处理降级逻辑,例如,响应一个状态码告知服务降级接口调用失败。
我们还需要将该ServiceDegradeFallback
注册到Feign
的Clinet
环境隔离的容器中。编写配置类SentinelFeignConfig
,将SentinelFeignConfig
添加到@FeignClient
注解的configuration
属性。
在SentinelFeignConfig
中注册ServiceDegradeFallback
。
当满足熔断条件时,Sentinel
会抛出一个DegradeException
异常,如果配置了fallback
,那么Sentinel
会从Bean
工厂中根据取fallback
属性配置的类型取一个Bean
调用相同的方法。
但有一点不足的地方,我们在ServiceDegradeFallback
中无法获取异常的类型,无法判断是否是熔断降级,只能把所有情况都当初熔断降级处理。