zoukankan      html  css  js  c++  java
  • 使用Sentinel实现熔断降级

    降级策略

    我们通常用以下几种方式来衡量资源是否处于稳定的状态:

    • 平均响应时间 (DEGRADE_GRADE_RT):当资源的平均响应时间超过阈值(DegradeRule 中的 count,以 ms 为单位)之后,资源进入准降级状态。接下来如果持续进入 5 个请求,它们的 RT 都持续超过这个阈值,那么在接下的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)之内,对这个方法的调用都会自动地返回(抛出 DegradeException)。注意 Sentinel 默认统计的 RT 上限是 4900 ms,超出此阈值的都会算作 4900 ms,若需要变更此上限可以通过启动配置项 -Dcsp.sentinel.statistic.max.rt=xxx 来配置。
    • 异常比例 (DEGRADE_GRADE_EXCEPTION_RATIO):当资源的每秒异常总数占通过量的比值超过阈值(DegradeRule 中的 count)之后,资源进入降级状态,即在接下的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
    • 异常数 (DEGRADE_GRADE_EXCEPTION_COUNT):当资源近 1 分钟的异常数目超过阈值之后会进行熔断。

    注意:异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(BlockException)不生效。为了统计异常比例或异常数,需要通过 Tracer.trace(ex) 记录业务异常。

    针对这些规则,Sentinel中给出了响应的字段来设置:

    Sentinel限流中最重要的处理链:

    public class DefaultSlotChainBuilder implements SlotChainBuilder {
    
        @Override
        public ProcessorSlotChain build() {
            ProcessorSlotChain chain = new DefaultProcessorSlotChain();
            chain.addLast(new NodeSelectorSlot());
            chain.addLast(new ClusterBuilderSlot());
            chain.addLast(new LogSlot());
            chain.addLast(new StatisticSlot());
            chain.addLast(new SystemSlot());
            chain.addLast(new AuthoritySlot());
            chain.addLast(new FlowSlot());
            chain.addLast(new DegradeSlot());
    
            return chain;
        }
    
    }

    可以看到最后一个Slot,就是熔断降级部分,他与限流是可以并存的。

    实战例子:

    服务类:

    package com.xin.sentinel.demo.service;
    
    import com.alibaba.csp.sentinel.Entry;
    import com.alibaba.csp.sentinel.SphU;
    import com.alibaba.csp.sentinel.annotation.SentinelResource;
    import com.alibaba.csp.sentinel.slots.block.BlockException;
    import com.alibaba.csp.sentinel.slots.block.RuleConstant;
    import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
    import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
    import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
    import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
    import com.xin.sentinel.demo.dao.DB;
    import com.xin.sentinel.demo.entity.User;
    import org.springframework.stereotype.Service;
    
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    import java.util.concurrent.TimeUnit;
    
    @Service
    public class RTUserService {
    
        public static final String USER_DEGRADERULE_RES = "userDegradeRuleResource";
        public static final String USER_DEGRADERATIORULE_RES = "userDegradeRATIORuleResource";
    
        public RTUserService(){
            //initDegradeRTRule();
            initDegradeRATIORule();
        }
    
        private static void initDegradeRTRule() {
            List<DegradeRule> rules = new ArrayList<DegradeRule>();
            DegradeRule rule = new DegradeRule();
            rule.setResource(USER_DEGRADERULE_RES);
            // set threshold rt, 100 ms
            rule.setCount(100);//资源的平均响应时间超过阈值100 ms,进入降级
            rule.setGrade(RuleConstant.DEGRADE_GRADE_RT);//平均响应时间 (DEGRADE_GRADE_RT)
            rule.setTimeWindow(3);//持续降级的时间窗口3秒
            rules.add(rule);
            DegradeRuleManager.loadRules(rules);
        }
    
    
        private static void initDegradeRATIORule() {
            List<DegradeRule> rules = new ArrayList<DegradeRule>();
            DegradeRule rule = new DegradeRule();
            rule.setResource(USER_DEGRADERATIORULE_RES);
            // 当资源的每秒异常总数占通过量的比值超过阈值(DegradeRule 中的 count)49% 之后,资源进入降级状态
            rule.setCount(0.49);
            rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO);
            rule.setTimeWindow(10);
            rules.add(rule);
            DegradeRuleManager.loadRules(rules);
        }
    
    
        /**
         * 通过 @SentinelResource 注解定义资源并配置 blockHandler 和 fallback 函数来进行限流之后的处理
         * @param id
         * @return
         */
        @SentinelResource(blockHandler = "blockHandlerForGetUser", fallback = "fallbackHandlerForGetUser")
        public User getUserByRTDegradeRule(int id) {
            Entry entry = null;
            try {
    
                entry = SphU.entry(USER_DEGRADERULE_RES);
                //第5个请求开始超过阀值100ms
                if (id>5){
                    TimeUnit.MILLISECONDS.sleep(150);
                }
                // 业务代码
                User user = new User();
                user.setId(id);
                user.setName("user-" + id);
                DB.InsertUser(user); //长耗时的工作
                return user;
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BlockException e) {
                e.printStackTrace();
                System.out.println(e+"[getUser] has been protected! id="+ id);
                return new User("block user"+id);
            } finally {
                if (entry != null) {
                    entry.exit();
                }
            }
            return null;
        }
    
        @SentinelResource(blockHandler = "blockHandlerForGetUser", fallback = "fallbackHandlerForGetUser")
        public User getUserByRATIODegradeRule(int id) {
            Entry entry = null;
            try {
    
                entry = SphU.entry(USER_DEGRADERATIORULE_RES);
                //第5个请求开始出现异常
                if (id>5){
                    throw new RuntimeException("throw runtime ");
                }
                // 业务代码
                User user = new User();
                user.setId(id);
                user.setName("user-" + id);
                DB.InsertUser(user); //长耗时的工作
                return user;
            }
            catch (Exception e) {
                e.printStackTrace();
                System.out.println(e+"[getUser] has been protected! id="+ id);
    
            } finally {
                if (entry != null) {
                    entry.exit();
                }
            }
            return new User("block user"+id);
        }
    
    
        // blockHandler 函数,原方法调用被限流/降级/系统保护的时候调用
        public User blockHandlerForGetUser() {
            return new User("block user");
        }
    
        public User fallbackHandlerForGetUser() {
            return new User("fallback user");
        }
    
    
    
    }
    View Code

    控制器:

    package com.xin.sentinel.demo.controller;
    
    import com.xin.sentinel.demo.entity.User;
    import com.xin.sentinel.demo.service.RTUserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import java.util.ArrayList;
    import java.util.List;
    
    @Controller
    public class RTDemo {
    
        @Autowired
        private RTUserService userService;
    
        @GetMapping("/getUserByRTDegradeRule")
        public @ResponseBody
        List<User> getUserByRTDegradeRule() throws InterruptedException {
    
            List<User> usersList = new ArrayList<User>();
            for (int i=0;i<50;i++){
                usersList.add(userService.getUserByRTDegradeRule(i));
            }
    
            return usersList;
        }
    
        @GetMapping("/getUserByRATIODegradeRule")
        public @ResponseBody
        List<User> getUserByRATIODegradeRule() throws InterruptedException {
    
            List<User> usersList = new ArrayList<User>();
            for (int i=0;i<50;i++){
                usersList.add(userService.getUserByRATIODegradeRule(i));
            }
    
            return usersList;
        }
    
    
    }
    View Code

    可以看到,在使用getUserByRTDegradeRule规则时,第16个输出为block user,即进入了超时熔断。

    项目源码

    Sentinel.zip

  • 相关阅读:
    myeclipse包的层数和package的层数不一致
    myeclipse提示:Syntax error on tokens, delete these tokens怎么解决
    智能指针 shared_ptr
    一次读入全部文件到内存中
    条件变量 condition_variable wait_until
    条件变量 condition_variable wait_for
    条件变量 condition_variable wait
    ffmpeg 交叉编译 版本4.0.4
    curl 交叉编译 支持http2和openssl
    nghttp2 交叉编译
  • 原文地址:https://www.cnblogs.com/starcrm/p/12921357.html
Copyright © 2011-2022 走看看