美文网首页
Sentinel | 降级

Sentinel | 降级

作者: 乌鲁木齐001号程序员 | 来源:发表于2020-07-23 16:09 被阅读0次

    下游服务挂了造成雪崩

    微服务间的依赖.png
    • 请求进来访问 A,A 需要调 B,C,D;
    • D 挂了;
    • A 调 D 的线程就挂起;
    • 不停的有请求访问 A,A 就不停的开新线程调 D;
    • 当 A 开的线程数超过阈值,A 也失去响应了;
    • 依赖 A 的服务慢慢的也失去响应,造成连锁的反应;
    • 根上其实就是服务 D 不行了,但 D 造成了和它有依赖关系的服务都不行了;
    • 这就是雪崩;
    • 要避免雪崩,就是当 D 不行了,不会把调用它的服务都拖死;

    熔断器

    熔断器的加入.png
    • 上游服务和下游服务之间加了一个熔断器;
    • 熔断器平时处于关闭状态;
    • A 一旦发现 D 不可用了,熔断器就会打开,此时,A 再调 D 的时候,发现 D 不行了,请求不会再发到 D 上,而是从熔断器直接就返回了;
    • A 不会再等 D 的响应,后面再有访问 A 的请求,也不会造成线程的堆积;

    熔断器详解图

    熔断器详解图.png
    • 熔断器其实是一个 3 个状态的状态机;
    • 请求进来熔断器,如果熔断器是关闭状态,请求就会放给后面的服务,后面的服务如果正常返回 ,没问题;如果后面的服务出现问题,比如数据库连不上了,抛异常了,网络抖动,服务压力大导致响应时间变长,服务超时,在熔断器这都会做一个统计;熔断器一共放过去 10 个请求,5 个超时,3 个报错;可以配置熔断器,在什么情况下,从关闭状态到打开状态,比如 1s 过去 10 个请求,有 5 个超时,就把熔断器打开;
    • 如果熔断器打开,请求进入熔断器,从熔断器就直接返回了;
    • 如果后面的服务是因为网络抖动,服务压力瞬间变大,当熔断器打开一段时间后,后面的服务会自己恢复,这时候,需要一个机制,让熔断器知道后面的服务正常了,让熔断器重新回到关闭状态;这个机制就是一个定时任务,定时的时间是可以配置的,当时间到了,熔断器会变成版打开状态,放一个请求给后面的服务,如果后面的服务成功处理了这个请求,熔断器就从半打开状态变成关闭状态,请求后可以到达后面的服务了;如果放过去的请求还是失败,熔断器回到打开状态,等待下一个时间窗口,尝试下一次试探,直到试探成功;

    降级

    • 降级就是,当熔断器打开的时候,可以指定一个更简化的处理;
    • 比如后面的服务是一个推荐服务,如果后面的服务挂了,就把预先设计好的列表,响应给请求;
    • 用户此时看到的列表,不是针对他实时计算推荐出来的,而是预先设定好的;
    • 降级是将的响应的质量,但不会造成用户端没有响应;

    用代码配置 Sentinel 的熔断规则

    Sentinel 的三种失败指标
    • 一秒内(请求数大于等于 5)响应时间超过某个值:RuleConstant.DEGRADE_GRADE_RT;
    • 一秒内(请求数大于等于 5)的错误比率:RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO;
    • 一分钟内的错误数量:RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT;
    代码
    @Component
    public class SentinelConfig implements ApplicationListener<ContextRefreshedEvent> {
    
        /**
         * 整个系统启动好了之后,会这行整个方法;
         * 这里要声明一个规则;
         * 这里是用代码的方式控制规则的制定,这种方式的控制程度是最高的,所有的细节都可以控制,缺点就是麻烦;
         * @param contextRefreshedEvent
         */
        @Override
        public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
            fusingRule();
        }
    
        /**
         * 熔断规则
         */
        private void fusingRule() {
            DegradeRule rule = new DegradeRule();
            rule.setResource("createOrder");
    
            // 1s 内的请求数超过 5 的情况下,响应时间超过多少,打开熔断器;
            rule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
    
            // 如果响应时间超过 10ms,就记一次数;如果 1s 内有 5 个请求,5 个请求都超时了,就熔断;
            rule.setCount(10);
    
            // 熔断的持续时间为 10s,熔断时间超过 10s 就进入半打开状态;
            rule.setTimeWindow(10);
    
            List<DegradeRule> degradeRules = new ArrayList<>();
            degradeRules.add(rule);
            DegradeRuleManager.loadRules(degradeRules);
        }
    
    }
    

    使用 Sentinel 实现降级

    正常的业务方法
    @PostMapping
    @PreAuthorize("hasRole('ROLE_ADMIN')")
    @SentinelResource(value = "createOrder", blockHandler = "doOnBlock")
    public OrderInfo create(@RequestBody OrderInfo info, @AuthenticationPrincipal String username)
            throws InterruptedException {
    
        // 这里的代码就是资源 createOrder
        log.info("user is " + username);
    
        Thread.sleep(50);
    
        return info;
    }
    
    发生熔断后的降级方法
    /**
     * 降级方法:一定是 public,返回值和参数要和
     * @SentinelResource(value = "createOrder", blockHandler = "doOnBlock") 标记的方法一样,只是多出一个参数;
     * @param info
     * @param username
     * @param exception
     * @return
     * @throws InterruptedException
     */
    public OrderInfo doOnBlock(@RequestBody OrderInfo info,
                               @AuthenticationPrincipal String username,
                               BlockException exception) throws InterruptedException {
    
        // 降级逻辑,比如返回预先准备好的数据啥的
        log.info("Blocked by : " + exception.getClass().getSimpleName());
    
        return info;
    }
    

    相关文章

      网友评论

          本文标题:Sentinel | 降级

          本文链接:https://www.haomeiwen.com/subject/sahhlktx.html