SpringCloud:Sentinel3

149 阅读4分钟

Sentinel 隔离和降级

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第10天,点击查看活动详情

如果有需要可以查看官方文档sentinelguard.io/zh-cn/docs/…

流量控制是一种预防措施,能够减缓雪崩发生的情况,但是无法完全隔绝。如果想要将雪崩问题控制在一定的范围,需要通过线程隔离和熔断降级这两个手段了。

  • **线程隔离:**消费者远程调用提供者方法的时候,为每个远程调用的请求分配独立线程池。当某一个提供者出现故障时,最多消耗该提供者对应请求的独立线程池资源,避免消费者的所有资源被耗尽。

    image-20220809162742696

  • **熔断降级:**在消费者远程调用提供者的过程中,加入一个断路器。断路器统计提供者响应失败的次数,若 失败次数/总请求次数 比例过高,则熔断该业务,不允许再访问该服务的提供者。

    image-20220809165555986

无论是线程隔离或者熔断降级都是对提供者的限制和监管,对消费者的保护。在提供者出现故障的时候对消费者通过线程隔离、熔断降级进行保护。

我们的微服务远程调用通过 Feign 完成,因此我们将 Feign 和 Sentinel 进行整合,在 Feign 中实现线程隔离和熔断降级。

1. FeignClient 整合 Sentinel

  • Feign 整合 Sentinel 步骤:
    1. 在application.yml中配置:feign.sentienl.enable=true
    2. 给FeignClient编写FallbackFactory并注册为Bean
    3. 将FallbackFactory配置到FeignClient

1.1 修改配置,开启 Sentinel 功能

  • 修改消费者的 application.yml 文件,开启 Feign 的 Sentinel 功能:

    feign:
      sentinel:
        enabled: true # 开启 feign 对 sentinel 的支持
    

1.2 编写失败降级逻辑

当提供者出现故障的时候,对应的请求返回的是异常信息。我们不能让异常信息赤裸裸的展示在用户面前,通常会给用户返回一个友好提示或默认结果。这个就是请求失败后的降级逻辑,也叫做失败降级逻辑。

  • 给 Feign 编写失败后的降级逻辑,通常有两种方法:

    1. FallbackClass,无法对远程调用做异常处理
    2. FallbackFactory,可以对远程调用的异常做处理

    我们通常选择第二种方法做失败降级处理

接下来我们将演示第二种方法 FallbackFactory 处理方法

  1. 在 Feign 里定义 FallbackFactory

    image-20220817224623517

    代码:

    package cn.itcast.feign.clients.fallback;
    
    import cn.itcast.feign.clients.UserClient;
    import cn.itcast.feign.pojo.User;
    import feign.hystrix.FallbackFactory;
    import lombok.extern.slf4j.Slf4j;
    
    /**
     * @author HGD
     * @date 2022/8/17 12:09
     */
    @Slf4j
    public class UserClientFallbackFactory implements FallbackFactory<UserClient> {
        @Override
        public UserClient create(Throwable throwable) {
            return new UserClient() {
                @Override
                public User findById(Long id) {
                    log.error("查询用户失败", throwable);
                    return new User();
                }
            };
        }
    }
    
  2. 将上面的 FallbackFactory 注册成 Bean

    package cn.itcast.feign.config;
    
    import cn.itcast.feign.clients.fallback.UserClientFallbackFactory;
    import feign.Logger;
    import org.springframework.context.annotation.Bean;
    
    public class DefaultFeignConfiguration {
        @Bean
        public Logger.Level logLevel(){
            return Logger.Level.BASIC;
        }
    
        /**
         * 将 FallbackFactory 注册到 Bean 中
         * @return new UserClientFallbackFactory();
         */
        @Bean
        public UserClientFallbackFactory userClientFallbackFactory() {
            return new UserClientFallbackFactory();
        }
    }
    
    
  3. 在 Feign 中提供者的接口中添加 @FeignClient(fallbackFactory = FallbackFactory.class)注解

    image-20220817225235842

    代码:

    package cn.itcast.feign.clients;
    
    
    import cn.itcast.feign.clients.fallback.UserClientFallbackFactory;
    import cn.itcast.feign.pojo.User;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    
    @FeignClient(value = "userservice", fallbackFactory = UserClientFallbackFactory.class)
    public interface UserClient {
        @GetMapping("/user/{id}")
        User findById(@PathVariable("id") Long id);
    }
    

完成所有步骤之后重启消费者的服务,访问一下涉及远程调用的业务,然后查看 Sentinel 控制台

image-20220817225440411

2. 线程隔离(舱壁模式)

2.1 线程隔离的实现方式

线程隔离通过两种方式实现:

  • 线程池隔离

    为每个远程调用的请求分配独立线程池,利用线程池本身实现隔离效果

    image-20220817231652668

  • 信号量隔离

    不创建线程池,而是计数器模式,记录业务使用的线程数量,达到信号量上限时,禁止新的请求

    image-20220817231231602

方式二是 Sentinel 默认方法

  • 两者优缺点

    优点缺点场景
    信号量隔离轻量级,无额外开销不支持主动超时,不支持异步调用高频使用,高输出
    线程池隔离支持主动超时,支持异步调用线程的额外开销比较大低扇出,调用较少的情况

    低扇出:一个类,尽可能不要去依赖别的类,就是所谓的low fan out

    主动超时:能主动控制方法执行的超时时间,如果超时了或有异常就抛出异常

2.2 Sentinel 的线程隔离

  • 配置规则

    image-20220817233216115

  • 案例

    1. 配置隔离规则

      选择 Feign 接口后面的流控按钮:

      image-20220817233416091

      填写表单:

      image-20220817233510142

    2. 使用 JMeter 测试

      选择《阈值类型-线程数<2》:

      image-20210716124229894

      一次发生10个请求,有较大概率并发线程数超过2,而超出的请求会走之前定义的失败降级逻辑。

      查看运行结果:

      image-20210716124147820

      发现虽然结果都是通过了,不过部分请求得到的响应是降级返回的null信息。

2.3.总结

线程隔离的两种手段是?

  • 信号量隔离

  • 线程池隔离

信号量隔离的特点是?

  • 基于计数器模式,简单,开销小

线程池隔离的特点是?

  • 基于线程池模式,有额外开销,但隔离控制更强