上一篇:Sentinel源码阅读(一)
本文主要包括Sentinel的熔断降级与滑动窗口算法部分。
熔断降级
前文说了,每一种规则都是责任链中的一个节点,对应不同的实现类,熔断降级的类就是DegradeSlot,位于com.alibaba.csp.sentinel.slots.block.degrade包下。目录结构如下:
除了DegradeSlot,还有
-
CircuitBreaker:断路器,并有异常数断路器ExceptionCircuitBreaker与RT断路器ResponseTimeCircuitBreaker
-
DegradeException:BlockException的子类,降级抛出的是这个异常类
-
DegradeRule:降级规则
DegradeSlot的entry方法首先执行performChecking方法,核心逻辑都在这里。
@Override public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, boolean prioritized, Object... args) throws Throwable { performChecking(context, resourceWrapper); fireEntry(context, resourceWrapper, node, count, prioritized, args); } void performChecking(Context context, ResourceWrapper r) throws BlockException { List<CircuitBreaker> circuitBreakers = DegradeRuleManager.getCircuitBreakers(r.getName()); if (circuitBreakers == null || circuitBreakers.isEmpty()) { return; } for (CircuitBreaker cb : circuitBreakers) { if (!cb.tryPass(context)) { throw new DegradeException(cb.getRule().getLimitApp(), cb.getRule()); } } }
第一步是根据资源标识获取断路器list。DegradeRuleManager.getCircuitBreakers是直接从其内部一个map get资源标识映射的断路器的。而这个map的初始化在DegradeRuleManager.RulePropertyListener::reloadFrom方法中
private synchronized void reloadFrom(List<DegradeRule> list) { Map<String, List<CircuitBreaker>> cbs = buildCircuitBreakers(list); Map<String, Set<DegradeRule>> rm = new HashMap<>(cbs.size()); for (Map.Entry<String, List<CircuitBreaker>> e : cbs.entrySet()) { assert e.getValue() != null && !e.getValue().isEmpty(); Set<DegradeRule> rules = new HashSet<>(e.getValue().size()); for (CircuitBreaker cb : e.getValue()) { rules.add(cb.getRule()); } rm.put(e.getKey(), rules); } DegradeRuleManager.circuitBreakers = cbs; DegradeRuleManager.ruleMap = rm; }
DegradeRule是从配置中取的(或者手动构造)不再赘述,这个方法读取DegradeRule列表,并将其转化为CircuitBreaker。转换的方法比较简单,见DegradeRuleManager::newCircuitBreakerFrom。
然后实际上就是遍历断路器列表,执行其tryPass方法判断调用是否能通过,不通过则抛出DegradeException异常。因此下面重点看下断路器CircuitBreaker类。
Sentinel的断路器借鉴了一篇经典文章: