分布式系统为了保证系统稳定性,在服务治理的限流中会根据不同场景进行限流操作,常见的限流算法有:
令牌桶:可容忍一定突发流量的速率的限流,令牌桶算法的原理是系统以恒定的速率产生令牌,然后把令牌放到令牌桶中,令牌桶有一个容量,当令牌桶满了的时候,再向其中放令牌,那么多余的令牌会被丢弃;当想要处理一个请求的时候,需要从令牌桶中取出一个令牌,如果此时令牌桶中没有令牌,那么则拒绝该请求。
漏斗:固定速率限流,可以启动整流作用。
在分析sentinel限流之前,我们先看下sentinel是什么,官网说明如下:
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式服务架构的流量控制组件,主要以流量为切入点,从流量控制、熔断降级、系统自适应保护等多个维度来帮助您保障微服务的稳定性。
从限流角度来看,sentinel的限流有2种控制维度,一个是qps,一个是并发数。
qps这个很好理解,也就是每秒处理请求量,当超过设定阈值时,会进行流控,策略有如下几种:拒绝、排队(一定时长)等。
并发数这个就是当前线程运行数,类似于hystrix,只不过sentinel是进行线程个数统计判断是否达到线程设定值,而hystrix是根据不同线程池来做的。
sentinel中处理流程是一个责任链,不同功能的逻辑抽象成不同的ProcessorSlot组合在一起,比如有限流的FlowSlot、打日志的LogSot、数据统计的StatisticSlot。下面重点看限流的com.alibaba.csp.sentinel.slots.block.flow.FlowSlot:
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, boolean prioritized, Object... args) throws Throwable { // 是否触发限流检查 checkFlow(resourceWrapper, context, node, count, prioritized); // 继续往下一个节点走 fireEntry(context, resourceWrapper, node, count, prioritized, args); } public void checkFlow(Function<String, Collection<FlowRule>> ruleProvider, ResourceWrapper resource, Context context, DefaultNode node, int count, boolean prioritized) throws BlockException { Collection<FlowRule> rules = ruleProvider.apply(resource.getName()); for (FlowRule rule : rules) { // 多个限流规则检查 if (!canPassCheck(rule, context, node, count, prioritized)) { throw new FlowException(rule.getLimitApp(), rule); } } } // canPassCheck -> passLocalCheck private static boolean passLocalCheck(FlowRule rule, Context context, DefaultNode node, int acquireCount, boolean prioritized) { return rule.getRater().canPass(selectedNode, acquireCount, prioritized); }