Spring Cloud & Alibaba 实战: Sentinel+Nacos实现流控、熔断降级,赋能拥有降级功能的...

目录

  • 二. Docker部署Sentinel Dashboard

    • 5. 网关流控客户端标识
    • 7. Nacos添加网关流控规则
    • 9. 自定义网关流控异常
  • 六. Sentinel整合Feign熔断降级

一. Sentinel概念

1. 什么是Sentinel?

Sentinel是阿里中间件团队研发面向分布式服务架构的轻量级高可用流量控制组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性。于2012年诞生,后续在阿里巴巴集团内部迅速发展,成为基础技术模块,覆盖了所有的核心场景,Sentinel也因此积累了大量的流量归整场景及生产实践。最终在2018年7月宣布对外界开源。

Sentinel的基本概念:

  • 资源: Sentinel 的关键概念,可以是Java应用程序中任何内容,通过Sentinel API定义的代码,能够被Sentinel保护起来,大部份情况下,可以使用方法签名,URL,甚至服务名称作为资源名
  • 规则: 围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。

Sentinel分为两个部分:

  • 控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器,也就是sentinel-dashboard-1.8.1.jar。
  • 核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。

2. Sentinel功能特性

image

从上图可知Sentinel的功能特性很多以及应用场景非常广泛,以下就 限流熔断降级 这几个常见的功能特性以及意义进行简要说明

限流:限流同时也叫做流量控制,原理是监控应用流量的QPS或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。

image

熔断降级:除了流量控制以外,及时对调用链路中的不稳定因素进行熔断也是Sentinel的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源不稳定,最终会导致请求发生堆积,进而导致级联错误。Sentinel当检测到调用链路中某个资源出现不稳定的表现(请求响应时间长或异常比例升高),则对这个资源的调用进行限制,让请求快速失败,避免影响到其他资源而导致级联故障。

  • 熔断: 拒绝流量访问,当系统恢复正常时关闭熔断。
  • 降级: 将次要服务降级,停止服务,将系统资源放出来给核心功能
image

3. Sentinel VS Hystrix

以下摘自Sentinel官方文档,详情点击 Sentinel 与 Hystrix 的对比

Sentinel Hystrix
隔离策略 信号量隔离 线程池隔离/信号量隔离
熔断降级策略 基于响应时间或失败比率 基于失败比率
实时指标实现 滑动窗口· 滑动窗口(基于 RxJava)
规则配置 支持多种数据源 支持多种数据源
扩展性 多个扩展点 插件的形式
基于注解的支持 支持 支持
限流 基于 QPS,支持基于调用关系的限流 有限的支持
流量整形 支持慢启动、匀速器模式 不支持
系统负载保护 支持 不支持
控制台 开箱即用,可配置规则、查看秒级监控、机器发现等 不完善
常见框架的适配 Servlet、Spring Cloud、Dubbo、gRPC 等 Servlet、Spring Cloud Netflix

Sentinel 和 Hystrix 的原则是一致的,但是在限制手段上,Sentinel和Hystrix采取了完全不一样的方法。

  • Hystrix: 通过线程池隔离,来对依赖(在Sentinel的概念对应 资源 )进行了隔离。好处在于资源之间做到最彻底的隔离,缺点是除了增加了线程切换的成本,还需要预先给各个资源做线程池大小的分配。
  • Sentinel : 通过并发线程数进行限制和响应时间对资源进行降级两种手段。

二. Docker部署Sentinel Dashboard

1. 拉取镜像

docker pull bladex/sentinel-dashboard

2. 启动容器

docker run --name sentinel -d -p 8858:8858 -d bladex/sentinel-dashboard

3. 访问测试

访问: http://IP:8858

用户名/密码:sentinel/sentinel

image

三. Sentinel网关流控

1. 网关流控定义

Sentinel支持对Spring Cloud Gateway、Zuul等主流的API Gataway 进行限流,作用在网关的流控称之为 网关流控 ,其实现原理请点击 网关限流 进入官方Wiki查看。

这里只把原理图从官方文档摘出来,需多关注图中提到的模块名和几个类名,因为都是 核心 级别的存在。

image

规则类型 gw-flowgw-api-group 为网关流控规则,具体类型请查看规则类型枚举 RuleType

/**
* flow 流控规则
*/
FLOW("flow", FlowRule.class),
/**
* degrade 降级规则
*/
DEGRADE("degrade", DegradeRule.class),
/**
* param flow 热点规则
*/
PARAM_FLOW("param-flow", ParamFlowRule.class),
/**
* system 系统规则
*/
SYSTEM("system", SystemRule.class),
/**
* authority 授权规则
*/
AUTHORITY("authority", AuthorityRule.class),
/**
* gateway flow 网关限流规则
*/
GW_FLOW("gw-flow","com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule"),
/**
* api 用户自定义的 API 定义分组,可以看做是一些 URL 匹配的组合
*/
GW_API_GROUP("gw-api-group","com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition");
image

2. 网关流控规则

Field 说明 默认值
resource 资源名称,网关route或自定义API分组名称(注:网关route这里的值不是route.id,可调试
resourceMode 限流资源类型,网关route【0】或自定义API分组【1】(详细查看 GatewayFlowRuleSentinelGatewayConstants 网关route
grade 限流阈值类型,QPS【1】或线程数【0】 QPS
count 限流阈值,QPS阈值或线程数值
intervalSec 统计时间间隔,单位秒 1秒
controlBehavior 流控效果,目前支持快速失败【0】和匀速排队【1】 快速失败
burst 应对突发请求时额外允许的请求数目
maxQueueingTimeoutMs 匀速排队模式下的最长排队时间,单位毫秒,仅在匀速排队模式下生效
paramItem 参数属性配置,parseStrategy:提取参数策略(0:Clien IP,1:Remote HOST,2:Header,3:请求参数,4:Cookie);fieldName:若提取策略是Header模式或者URL参数模式,则需要指定header名称或URL参数名称;pattern:参数值的匹配模式;matchStrategy:参数值的匹配策略,支持精确匹配,子串匹配和正则匹配。

3. 导入依赖

<!-- Sentinel流量控制、熔断降级 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- Sentinel规则持久化至Nacos配置 -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

4. 网关配置

先放在本地Spring Boot配置文件bootstrap-dev.yml中,后面测试通过把后再把Sentinel配置放至Nacos

spring:
 cloud:
 nacos:
      # 注册中心
 discovery:
 server-addr: http://localhost:8848
      # 配置中心
 config:
 server-addr: ${spring.cloud.nacos.discovery.server-addr}
 file-extension: yaml
 sentinel:
 enabled: true # sentinel开关
 eager: true
 transport:
 dashboard: localhost:8080 # Sentinel控制台地址
 client-ip: localhost
 datasource:
        # 网关限流规则,gw-flow为key,随便定义
 gw-flow:
 nacos:
 server-addr: ${spring.cloud.nacos.discovery.server-addr}
 dataId: ${spring.application.name}-gw-flow-rules # 流控规则配置文件名:youlai-gateway-gw-flow-rules
 groupId: SENTINEL_GROUP
 data-type: json
 rule-type: gw-flow
        # 自定义API分组,gw-api-group为key,随便定义
 gw-api-group:
 nacos:
 server-addr: ${spring.cloud.nacos.discovery.server-addr}
 dataId: ${spring.application.name}-gw-api-group-rules # 流控规则配置文件名:youlai-gateway-gw-api-group-rules
 groupId: SENTINEL_GROUP
 data-type: json
 rule-type: gw-api-group

这里解释下配置中的datasource,因为在Sentinel添加流控规则之后,如果重启服务,之前配置的规则就会消失,所以这里需要持久化Sentinel配置,从上面的配置可以看出选择的是Nacos。不过这里先别急在Nacos添加网关流控规则,下文在测试确认需求后配置。

5. 网关流控客户端标识

网关流控和普通流控有很多区别,其中网关流控类型是 gw-flow ,普通流控类型是 flow

怎么标识流控是网关类型呢?

很多博客文章都没有着重此点,因为前阵子纠结于网关流控的面板和普通流控的面板不一致而去搜相关的资料,最后还是在Sentinel官方文档中找到此开关,就是需要在 youlai-gateway 网关应用添加JVM启动参数。

# 注:通过 Spring Cloud Alibaba Sentinel 自动接入的 API Gateway 整合则无需此参数
-Dcsp.sentinel.app.type=1

具体如下图:

image

6. 测试需求制定

在做好上面Sentinel Dashboard部署以及Spring Cloud Gateway整合Sentinel工作之后,Sentinel的两个部分(控制台和Java客户端)也就齐活了,那么接下来就进入测试。

下图简单的描述了OAuth2认证接口的流程,用户请求网关,网关(youlai-gateway)根据请求标识转发至认证中心,认证中心(youlai-auth)需要从系统服务(youlai-admin)获取数据库的用户信息再和请求携带的用户信息进行密码判读,成功则返回token给用户。

image

针对以上的OAuth2认证流程,提出来一个需求:

假设认证中心服务的QPS上限为10,系统服务的QPS上限为5,如何通过Sentinel实现限流控制?

温馨提示:留意下上图中的红线部分,你认为网关的流控是否能限制到与其间接相关的系统服务youlai-admin吗?

7. Nacos添加网关流控规则

进入Nacos控制台,添加网关流控规则,具体内容参考网关流控字段说明。

需要注意的是 资源名称resource不是路由中配置的route的id ,在开启Sentinel时调试SentinelGatewayFilter#filter方法可以看到自动生成的是固定前缀ReactiveCompositeDiscoveryClient_拼接应用名称${spring.application.name},所以在配置文件中一定要按照自动生成的规则配置resource的值。填写网关路由route的id,Sentinel的网关流控是无法生效的。

上面网关流控规则中,限制了认证中心youlai-auth的QPS上限为10,系统服务youlai-admin的QPS上限为5。

至于为什么这么设定,因为有个猜想需要验证,网关流控是否只能限制和直接关联的youlai-auth,而不能限制间接相关的youlai-admin。

如果通过的QPS是10,那说明网关流控不能控制间接相关youlai-admin,如果通过的QPS是5,则说明网关流控能控制间接相关的youlai-admin,至于结果,先留个悬念吧,看下文的测试结果。

已添加的网关流控规则如下图:

在Nacos添加了网关流控规则之后,会同步到Sentinel,进入Sentinel控制台查看

8. 网关流控测试

在完成上述步骤之后,接下来就进入真正的测试环节。

添加线程组

测试计划(鼠标右击)->添加->线程(用户)->线程组

image

因为youlai-auth的QPS处理上限为10,所以这里的线程数大于10即可看到被限制的请求

添加HTTP请求

OAuth2登录线程组(鼠标右击)->添加->取样器->HTTP请求

接口是通过网关转发到认证中心的认证接口获取token

添加察看结果树

因为要看请求的响应,所以这里添加察看结果树。

OAuth2登录线程组(鼠标右击)->添加->监听器->察看结果树

image

启动线程组测试

启动线程组,每秒15次认证请求,需要注意的是,如果测试计划有多个线程组,需禁用除了测试之外的其他线程组。

image

点击 察看结果树 查看请求的情况

image

进入Sentinel控制台,查看实时监控

可以看到1秒15次请求,因为流控设置的QPS上限是10,所以10次通过,被Sentinel拒绝了5次。

这个结果也直接说明了网关流控并不是万能的,不能限制OAuth2认证请求中与其间接相关 youlai-admin 的微服务,因为在网关流控设置了 youlai-admin 的QPS上线为5,但最后整条链路成功的却是10。既然 网关流控 无法应对此类场景,是否还有其他的办法来做到呢?当然有: 普通流控

9. 自定义网关流控异常

上面Sentinel限流的默认异常响应如下

{"code":429,"message":"Blocked by Sentinel: ParamFlowException"}

假如想自定义网关流控异常响应,该如何实现呢?

可以通过在GatewayCallbackManager上通过setBlockHandler方法注册回调实现,当请求被限流后,实现自定义的异常响应。

自定义异常代码:

>@PostConstruct
private void initBlockHandler() {
    BlockRequestHandler blockRequestHandler = (exchange, t) ->
        ServerResponse.status(HttpStatus.OK)
        .contentType(MediaType.APPLICATION_JSON)
        .body(BodyInserters.fromValue(ResultCode.FLOW_LIMITING.toString()));
    GatewayCallbackManager.setBlockHandler(blockRequestHandler);
}

JMeter中查看被限流的响应,可以看到已按照自定义的响应异常返回,其中 B0210 是Java开发手册上的关于 系统限流 的错误码

四. 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. 导入依赖

<!-- Sentinel流量控制、熔断降级 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- Sentinel规则持久化至Nacos配置 -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

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));
        }
    }
}

为了测试普通流控,首先关闭网关流控,排除一些异常干扰

image

添加获取当前登录用户信息的HTTP请求

image

因为此HTTP接口需要认证,所以需要在请求头添加token。鼠标右击HTTP请求->添加->配置元件->HTTP信息头管理

image

HTTP信息头管理器添加token

image

执行线程组,查看自定义异常生效

image

五. Sentinel熔断降级

1. 熔断降级概述

微服务架构都是分布式的,不同服务相互调用,组成复杂的调用链路。复杂的链路上某一环不稳定,就可能层层级联,最终导致整个链路都不可用。因此需要对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定的调用,避免局部不稳定因素导致正题的雪崩。熔断降级作为保护自身的手段,通常在客户端(调用端)进行配置。

2. 熔断策略

image

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. 微服务配置

<pre class="prettyprint hljs yaml" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">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
复制代码</pre>

5. Nacos添加熔断降级规则

image

方便看到异常熔断的效果,选择了 异常数 的熔断策略,毕竟数数比计算比例简单多了。资源名为getCurrentUser是怎么回事,不急下文提到。总之这里的配置的大概意思就是说针对getCurrentUser资源,如果请求该接口出现了异常,则进行熔断,熔断时长为5秒。

6. 熔断异常模拟

先模拟一段在运行时发生异常的代码,在获取当前登录用户信息的接口埋个雷吧,注意到@SentinelResource注解中的value值getCurrentUser,也就是资源名称,联系上文,降级规则就是针对这个接口的方法。和上面在普通流控测试使用的是请求的路径不同,这里显示指定了资源名称和降级规则配置去做匹配。

image

@SentinelResource注解中的属性除了定义资源名的属性值value,还有两个属性有关降级处理分别是blockHandlerClass和blockHandler。意思是在单位时间接口异常数超过设置的阈值后进入熔断,在熔断时长(上面降级规则中设置的是5秒)范围内,再有请求过来访问该接口时,不会再走接口方法体内的逻辑。因为前面几次接口出现异常,那么敢断定接下来短时间内大概率还是会发生异常,所以索性就把后续的请求拦截避免,这也是熔断的意义。

在5秒的熔断时长内,如果再有请求访问该接口则会走降级的逻辑,也就是上图中指定的UserBlockHandler#handleGetCurrentUserBlock降级处理方法。

image

7. 熔断降级测试

在测试前,需要关闭网关那边流控,排除一些异常情况下的干扰。还有为了方便在JMeter查看结果,临时关闭全局异常处理器GlobalExceptionHandler。

还是拿上一节配置好的测试普通流控的线程组, 获取登录用户的信息 来作为熔断降级的测试案例,先看一下线程组的设置:

线程数为10,达到了熔断降级 最小请求数 (规则配置的5)的要求

image

获取登陆用户信息的接口信息

image

请求头添加token

image

测试线程组配置好之后看看使用不使用熔断降级和使用熔断降级的区别:

  • 不使用熔断降级

配置中关闭Sentinel

<pre class="prettyprint hljs yaml" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">sentinel:
enabled: false
复制代码</pre>

image
image

发现了吗?这种请求异常处理模式头铁啊,即使撞了南墙也不会回头,下次继续撞,下下次继续撞。ok,你没关系,那你有考虑一直被你撞的墙(服务器)了没?

  • 使用熔断降级

配置中开启Sentinel

<pre class="prettyprint hljs yaml" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">sentinel:
enabled: true
复制代码</pre>

image
image

通过日志可以看到进入主线代码的只有一次,后续的请求直接进入降级支线。

image

过了熔断时长5秒后,熔断器进入 探测恢复状态 (HALF-OPEN状态),这时候如果一个请求到主线没异常,关闭熔断器,让后续的请求都到主线过来;如果还是异常,打开熔断器。

六. Sentinel整合Feign熔断降级

1. Feign与Sentinel整合意义

在微服务架构中,声明式调用Feign在微服务之间调用充当重要的角色,在使用Feign的过程中如果为了系统的健壮性,一定会考虑如果因目标服务异常调用失败后的处理。

说到这里,相信对微服务有些了解的童鞋对下面的代码很熟悉:

image
image

上面两张图反应了Feign客户端在远程调用目标服务失败后,继而选择了降级的逻辑,像做人一样随时要给自己留一条后路,也就是稳,折射到程序亦是如此。这里只是一个降级的自定义异常返回,实际情况根据业务而定。

看到上面的代码,Feign在设计上就支持了降级的处理。这时候相信大家都会有一个疑问,Feign本身已经支持降级,那还需要Sentinel做什么?

换句话说可能会好理解一点,Sentinel给Feign带来了什么好处?

这个问题其实不难理解,先直接从字面上切入。

Feign是能够做到降级,Sentinel能够实现熔断降级,突显出来也就是 熔断 这一词,其中 熔断 的具体表象是怎样的?举个栗子说明:

假如客户端a通过feign调用b服务100次,此时b服务故障

  1. 没有熔断

    a的第1次请求走到b服务跟前,看着b躺在地上没动静,响应给客户端a说b没动静,让客户端a自己看着办吧。后面如此往复99次,每次a都需要走到b的面前然后再响应给客户端a,并告知b故障了。

  2. 有熔断

    a的第1次请求走到b服务跟前,看着b躺在地上没动静,这时候a就比较机智,判断b服务没有一时半刻是起不来了,就响应给客户端a并说这一时半刻钟的请求你自己看着处理吧,没有必要再到b面前,后面的99次请求就不会再到服务b那里了,省时省力。

想通过上面的举例说明熔断的意义和作用,因为Feign已经支持了降级,那再搭配上Sentinel的熔断,岂不是如虎添翼?

接下来将通过 有来项目 中的实例,认证中心【youlai-auth】在登录时需要远程feign调用系统服务【youlai-admin】的根据用户名获取用户信息的接口,来说明Sentinel如何整合Feign实现熔断降级及熔断降级的魅力。

2. 导入依赖

youlai-auth添加Sentinel和Nacos持久化规则依赖

<pre class="prettyprint hljs xml" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
复制代码</pre>

3. 微服务配置

youlai-auth开启Feign对Sentinel的支持

<pre class="prettyprint hljs yaml" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">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
复制代码</pre>

4. 熔断降级规则

在Nacos控制台添加youlai-auth的降级规则

image

<pre class="prettyprint hljs xquery" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">[
{
"resource": "GET:http://youlai-admin/api.admin/v1/users/username/{username}",
"grade": 2,
"count": 1,
"timeWindow": 5
}
]
复制代码</pre>

注意资源名称的生成规则,上面配置的意思是如果单位时间内出现了1次异常数,那没接下来5秒的时间窗口范围内的请求,因为熔断器打开,请求直接走降级逻辑。

5. 熔断降级测试

首先要模拟系统服务的根据用户名获取用户信息的接口异常,具体如下图:

image

配置JMeter线程组,单位时间1s内执行10个请求,具体配置在普通流控有说明,这里不做赘述。

image

结果在youlai-auth确实执行了10次请求,因为目标服务的异常走了降级的逻辑

image

但是真正进入youlai-admin的根据用户名获取用户信息的接口方法却只有1次,后续的9次请求直接走feign客户端的降级逻辑

image

上面的测试结果验证了Feign整合Sentinel之后实现了熔断和降级,至此Feign不再孤军奋战。

七. 结语

本文就Sentinel的流控、熔断降级从实战的角度去逐一验证。网关流控、普通流控能够在有限的资源能力保障系统的稳定运行,熔断降级能够在系统故障时提供兜底的处理逻辑保证系统的健壮性,支持降级的Feign整合Sentinel之后get到熔断的技能,至此熔断降级双剑合璧。

以前觉得微服务的限流、熔断降级是可有可无的存在,所以在开源项目中一直迟迟没有做相关的整合,当真正理解这其中的利害关系之后,微服务离不开这些。

当然本文提到的Sentinel功能的冰山一角,像限流延伸的还有热点key、IP限流、参数限流等等,具体选择使用根据场景,功能丰富,总会有你需要的。而且容易上手,是一个很不错的框架,内部的实现原理和还有算法很有必要去了解深入下。

如果有问题,欢迎加我微信(微信号:haoxianrui)

八. 附录

本文涉及的源码地址:

平台 地址
github github.com/hxrui/youla…
gitee gitee.com/youlaitech/…

文中的Sentinel规则配置已放置在项目document/nacos/SENTINEL_GROUP.zip,导入到Nacos控制台即可

image

当然你也可以本地启动Sentinel控制台,已经把官方的jar包放置在项目youlai-middleware/setinel/sentinel-dashboard-1.8.1.jar

<pre class="prettyprint hljs nginx" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">cd youlai-middleware/setinel
java -jar sentinel-dashboard-1.8.1.jar
复制代码</pre>

image

本地访问 http://localhost:8080即可进入Sentinel控制台

欢迎大家加入开源有来项目交流群,一起参与开源项目的开发。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,552评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,666评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,519评论 0 334
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,180评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,205评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,344评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,781评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,449评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,635评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,467评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,515评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,217评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,775评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,851评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,084评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,637评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,204评论 2 341

推荐阅读更多精彩内容