# Sentinel:服务的熔断

回顾前面篇笔记中的 “关于 Sentinel 的使用方式” 章节,在这里,我们在服务的 “请求发起方” 使用 Sentinel 整合 OpenFeign 进行熔断降级。

# 1. Sentinel 和 OpenFeign 整合

  1. 添加依赖

    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
    
  2. 添加配置(连接到 sentinel-dashboard)

    spring:
      cloud:
        sentinel:
          transport:
            dashboard: 127.0.0.1:8858
    
    # 日志设置
    logging:
      level:
        root: INFO
      pattern:
        console: "${CONSOLE_LOG_PATTERN:\
            %clr(${LOG_LEVEL_PATTERN:%5p}) \
            %clr(|){faint} \
            %clr(%-40.40logger{39}){cyan} \
            %clr(:){faint} \
            %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}}"
    
  3. 访问 sentinel-dashboard 可以看到类似如下页面:

    只需要完成上述的配置,代码不需要有任何的调整,我们就可以通过实时监控查看服务内的流量 QPS 以及平均响应时长等信息。

    警告

    只有服务接口被访问的情况下,在 sentinel 里面才可以看到监控信息。这可能会让你『等』一段时间。

    sentinel-plus-01

  4. 启用 OpenFeign 整合 Sentinel 的自动配置

    在 application.yaml 配置文件中添加如下配置,启用 Sentinel 与 OpenFeign 整合适配器。

    feign:
      sentinel:
        enabled: true
    

# 2. 熔断降级规则配置

在 sentinel-dashboard 上你可以看到有 降级规则,它指的就是『设置当满足什么条件时,对服务进行降级』。

sentinel-02

sentinel 支持 3 种降级规则:

# 3. 给 @FeignClient 注解配置异常回调

@FeignClient(
    name = "a-service", 
    fallback = AServiceClientImpl.class // 看这里,看这里,看这里
) 
public interface AServiceClient {
    ...
}

自定义一个类去实现 @FeignClient 接口,例如上面个所说的 AServiceClientImpl :

@Component
public class AServiceClientImpl implements AServiceClient {

    @Override
    public String index() {
        return "a-service index() 的 fallback 方法";
    }

    @Override
    public String slow() {
        return "a-service slow() 的 fallback 方法";
    }

}

AServiceClientImpl 类中处理接口降级逻辑。

警告

@FeignClient 接口的实现类必须是单例的,这就是为什么上面的 AServiceClientImpl 用上了 @Component 注解。

# 4. Sentinel 与 OpenFeign 整合实现原理

Sentinel 通过自己提供 SentinelInvocationHandler 替换 OpenFeign 的 InvocationHandler 实现请求拦截,而它在 SentinelInvocationHandler 的 invoke 方法中中,执行了熔断(和限流)的相关代码:

invoke() {

    1. 初始化上下文;
    try {
        2. 熔断、流控逻辑的判断,判断当前请求是否能继续执行;
        3. result = methodHandler.invoke(); // 真·逻辑:发起 HTTP 网络请求
    } catch (BlockException e) {
        4. 上述第 2 步未能通过,会抛出 BlockException ,表示请求被拒绝
        return;
    } catch (Exception e) {
        5. 业务异常,记录、统计异常信息
        throw e;
    } finally {
        6. 收尾工作:曾经创建的资源该回收的回收,该清除的清除
    }
}

另外,根据上述原理,你会发现 Sentinel 处在接口调用的最前端,因此 Sentinel 统计的指标数据即不会受 Ribbon 的重试影响也不会受 OpenFeign 的重试影响。