找回密码
 立即注册
首页 业界区 业界 Sentinel源码—6.熔断降级和数据统计的实现 ...

Sentinel源码—6.熔断降级和数据统计的实现

告陕无 4 天前
大纲
1.DegradeSlot实现熔断降级的原理与源码
2.Sentinel数据指标统计的滑动窗口算法
 
1.DegradeSlot实现熔断降级的原理与源码
(1)熔断降级规则DegradeRule的配置Demo
(2)注册熔断降级监听器和加载熔断降级规则
(3)DegradeSlot根据熔断降级规则对请求进行验证
 
(1)熔断降级规则DegradeRule的配置Demo
首先熔断降级规则的应用场景有如下两种:
 
场景一:在微服务架构中,当一个服务出现问题时,可以通过配置熔断降级规则,防止故障扩散,保护整个系统的稳定性。
 
场景二:在调用第三方API时,可以配置熔断降级规则,避免因第三方API不稳定导致自身系统不稳定。
 
然后从下图可知,熔断降级规则包含以下属性:
1.webp
属性一:熔断策略(grade)
这表示的是熔断降级规则的类型,取值范围分别是:
  1. RuleConstant.DEGRADE_GRADE_RT(慢调用比例)
  2. RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO(异常比例)
  3. RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT(异常数)
复制代码
其中,默认下的熔断降级规则是基于慢调用比例策略的,也就是默认值为:
  1. RuleConstant.DEGRADE_GRADE_RT
复制代码
属性二:熔断降级的阈值(count)
DegradeRule.count属性的具体含义取决于DegradeRule.grade属性的值。
  1. 如果grade为慢调用比例,则count表示慢调用比例阈值。
  2. 如果grade为异常比例,则count表示异常比例阈值。
  3. 如果grade为异常数,则count表示异常数阈值。
复制代码
属性三:熔断时长(timeWindow)
这表示的是熔断降级发生后的降级持续时间,在这段时间内对应的资源将被降级。
 
属性四:最小请求数(minRequestAmount)
这表示的是熔断降级统计周期内的最小请求总数。仅当周期内的请求总数达到此值时,才会根据grade和count进行熔断降级。默认值为:
  1. RuleConstant.DEGRADE_DEFAULT_MIN_REQUEST_AMOUNT
复制代码
属性五:慢调用比例阈值(slowRatioThreshold)
该属性当grade为慢调用比例时生效,取值范围为0到1之间的小数,表示慢调用请求占总请求的比例。
 
属性六:统计时长(statIntervalMs)
这表示的是熔断降级统计周期(单位:毫秒),默认值为1000毫秒(1秒)。在这个周期内,Sentinel会对请求进行统计,以判断是否要进行熔断降级。
  1. public class DegradeRule extends AbstractRule {
  2.     //熔断策略,表示的是熔断降级规则的类型
  3.     private int grade = RuleConstant.DEGRADE_GRADE_RT;
  4.     //熔断降级的阈值,具体含义取决于DegradeRule.grade属性的值
  5.     //如果grade为慢调用比例,则count表示慢调用比例阈值
  6.     //如果grade为异常比例,则count表示异常比例阈值
  7.     //如果grade为异常数,则count表示异常数阈值
  8.     private double count;
  9.     //熔断时长,即熔断降级发生后的降级持续时间,在这段时间内对应的资源将被降级
  10.     private int timeWindow;
  11.     //最小请求数,仅当周期内的请求总数达到此值时,才会根据grade和count进行熔断降级
  12.     private int minRequestAmount = RuleConstant.DEGRADE_DEFAULT_MIN_REQUEST_AMOUNT;
  13.     //慢调用比例阈值,仅当grade为慢调用比例时生效
  14.     private double slowRatioThreshold = 1.0d;
  15.     //统计时长,熔断降级统计周期,在这个周期内,Sentinel会对请求进行统计,以判断是否要进行熔断降级
  16.     private int statIntervalMs = 1000;
  17.     ...
  18. }
复制代码
接着如下便是DegradeRule的配置Demo:
  1. //Run this demo, and the output will be like:
  2. //1529399827825,total:0, pass:0, block:0
  3. //1529399828825,total:4263, pass:100, block:4164
  4. //1529399829825,total:19179, pass:4, block:19176 // circuit breaker opens
  5. //1529399830824,total:19806, pass:0, block:19806
  6. //1529399831825,total:19198, pass:0, block:19198
  7. //1529399832824,total:19481, pass:0, block:19481
  8. //1529399833826,total:19241, pass:0, block:19241
  9. //1529399834826,total:17276, pass:0, block:17276
  10. //1529399835826,total:18722, pass:0, block:18722
  11. //1529399836826,total:19490, pass:0, block:19492
  12. //1529399837828,total:19355, pass:0, block:19355
  13. //1529399838827,total:11388, pass:0, block:11388
  14. //1529399839829,total:14494, pass:104, block:14390 // After 10 seconds, the system restored
  15. //1529399840854,total:18505, pass:0, block:18505
  16. //1529399841854,total:19673, pass:0, block:19676
  17. public class SlowRatioCircuitBreakerDemo {
  18.     private static final String KEY = "some_method";
  19.     private static volatile boolean stop = false;
  20.     private static int seconds = 120;
  21.     private static AtomicInteger total = new AtomicInteger();
  22.     private static AtomicInteger pass = new AtomicInteger();
  23.     private static AtomicInteger block = new AtomicInteger();
  24.     public static void main(String[] args) throws Exception {
  25.         initDegradeRule();
  26.         registerStateChangeObserver();
  27.         startTick();
  28.         int concurrency = 8;
  29.         for (int i = 0; i < concurrency; i++) {
  30.             Thread entryThread = new Thread(() -> {
  31.                 while (true) {
  32.                     Entry entry = null;
  33.                     try {
  34.                         entry = SphU.entry(KEY);
  35.                         pass.incrementAndGet();
  36.                         //RT: [40ms, 60ms)
  37.                         sleep(ThreadLocalRandom.current().nextInt(40, 60));
  38.                     } catch (BlockException e) {
  39.                         block.incrementAndGet();
  40.                         sleep(ThreadLocalRandom.current().nextInt(5, 10));
  41.                     } finally {
  42.                         total.incrementAndGet();
  43.                         if (entry != null) {
  44.                             entry.exit();
  45.                         }
  46.                     }
  47.                 }
  48.             });
  49.             entryThread.setName("sentinel-simulate-traffic-task-" + i);
  50.             entryThread.start();
  51.         }
  52.     }
  53.     private static void registerStateChangeObserver() {
  54.         EventObserverRegistry.getInstance().addStateChangeObserver("logging",
  55.             (prevState, newState, rule, snapshotValue) -> {
  56.                 if (newState == State.OPEN) {
  57.                     System.err.println(String.format("%s -> OPEN at %d, snapshotValue=%.2f", prevState.name(), TimeUtil.currentTimeMillis(), snapshotValue));
  58.                 } else {
  59.                     System.err.println(String.format("%s -> %s at %d", prevState.name(), newState.name(), TimeUtil.currentTimeMillis()));
  60.                 }
  61.             }
  62.         );
  63.     }
  64.     private static void initDegradeRule() {
  65.         List<DegradeRule> rules = new ArrayList<>();
  66.         DegradeRule rule = new DegradeRule(KEY)
  67.             .setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType())//Max allowed response time
  68.             .setCount(50)
  69.             .setTimeWindow(10)//Retry timeout (in second)
  70.             .setSlowRatioThreshold(0.6)//Circuit breaker opens when slow request ratio > 60%
  71.             .setMinRequestAmount(100)
  72.             .setStatIntervalMs(20000);
  73.         rules.add(rule);
  74.         DegradeRuleManager.loadRules(rules);
  75.         System.out.println("Degrade rule loaded: " + rules);
  76.     }
  77.     private static void sleep(int timeMs) {
  78.         try {
  79.             TimeUnit.MILLISECONDS.sleep(timeMs);
  80.         } catch (InterruptedException e) {
  81.             // ignore
  82.         }
  83.     }
  84.     private static void startTick() {
  85.         Thread timer = new Thread(new TimerTask());
  86.         timer.setName("sentinel-timer-tick-task");
  87.         timer.start();
  88.     }
  89.     static class TimerTask implements Runnable {
  90.         @Override
  91.         public void run() {
  92.             long start = System.currentTimeMillis();
  93.             System.out.println("Begin to run! Go go go!");
  94.             System.out.println("See corresponding metrics.log for accurate statistic data");
  95.             long oldTotal = 0;
  96.             long oldPass = 0;
  97.             long oldBlock = 0;
  98.             while (!stop) {
  99.                 sleep(1000);
  100.                 long globalTotal = total.get();
  101.                 long oneSecondTotal = globalTotal - oldTotal;
  102.                 oldTotal = globalTotal;
  103.                 long globalPass = pass.get();
  104.                 long oneSecondPass = globalPass - oldPass;
  105.                 oldPass = globalPass;
  106.                 long globalBlock = block.get();
  107.                 long oneSecondBlock = globalBlock - oldBlock;
  108.                 oldBlock = globalBlock;
  109.                 System.out.println(TimeUtil.currentTimeMillis() + ", total:" + oneSecondTotal + ", pass:" + oneSecondPass + ", block:" + oneSecondBlock);
  110.                 if (seconds-- <= 0) {
  111.                     stop = true;
  112.                 }
  113.             }
  114.             long cost = System.currentTimeMillis() - start;
  115.             System.out.println("time cost: " + cost + " ms");
  116.             System.out.println("total: " + total.get() + ", pass:" + pass.get() + ", block:" + block.get());
  117.             System.exit(0);
  118.         }
  119.     }
  120. }
复制代码
 

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册