分布式系统为了保证系统稳定性,在服务治理的限流中会根据不一样场景进行限流操做,常见的限流算法有:html
令牌桶:可容忍必定突发流量的速率的限流,令牌桶算法的原理是系统以恒定的速率产生令牌,而后把令牌放到令牌桶中,令牌桶有一个容量,当令牌桶满了的时候,再向其中放令牌,那么多余的令牌会被丢弃;当想要处理一个请求的时候,须要从令牌桶中取出一个令牌,若是此时令牌桶中没有令牌,那么则拒绝该请求。java
漏斗:固定速率限流,能够启动整流做用。node
在分析sentinel限流以前,咱们先看下sentinel是什么,官网说明以下:算法
随着微服务的流行,服务和服务之间的稳定性变得愈来愈重要。Sentinel 是面向分布式服务架构的流量控制组件,主要以流量为切入点,从流量控制、熔断降级、系统自适应保护等多个维度来帮助您保障微服务的稳定性。架构
从限流角度来看,sentinel的限流有2种控制维度,一个是qps,一个是并发数。并发
qps这个很好理解,也就是每秒处理请求量,当超过设定阈值时,会进行流控,策略有以下几种:拒绝、排队(必定时长)等。app
并发数这个就是当前线程运行数,相似于hystrix,只不过sentinel是进行线程个数统计判断是否达到线程设定值,而hystrix是根据不一样线程池来作的。分布式
sentinel中处理流程是一个责任链,不一样功能的逻辑抽象成不一样的ProcessorSlot
组合在一块儿,好比有限流的FlowSlot、打日志的LogSot、数据统计的StatisticSlot。下面重点看限流的com.alibaba.csp.sentinel.slots.block.flow.FlowSlot
:ide
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); }
canPass校验目前有如下几种实现类:微服务
这几个实现类分别使用了以下几种限流算法:
DefaultController:令牌桶
RateLimiterController:漏斗
WarmUpController:冷启动的令牌桶
WarmUpRateLimiterController:冷启动的漏斗
sentinel中统计信息,好比qps、pass、block等信息都是在滑动时间窗口中维护的,好比时间戳是910时,统计信息会往对应800-1000的时间窗口更新,当时间戳是1001时,因为时间窗口只有5个(每一个200ms),所以会复用第一个时间窗口,在使用前会先进行初始化该窗口统计值。
对于默认的流控实现 DefaultController
,其是根据时间窗口的统计值是否达到了限流值来决定是否限流的,这也是把它归为令牌桶算法的缘由。漏斗算法实现RateLimiterController
,会记录上一次正常经过的时间戳信息(latestPassedTime),当判断是否限流时,会根据当前时间-latestPassedTime
是否大于间隔值,大于的话表示能够正常经过,小于的话表示刚刚已经有流程正常经过,这次须要排队等待,等待时间为指望时间戳-当前时间戳
,并发场景下,多个线程可能都会走到等待这里,所以须要(cas操做)判断当前需等待时间是否大于某个值,大于的话直接进行限流,再也不排队等待。
冷启动限流算法,即预热/冷启动方式。当系统长期处于低水位的状况下,当流量忽然增长时,直接把系统拉升到高水位可能瞬间把系统压垮。经过"冷启动",让经过的流量缓慢增长,在必定时间内逐渐增长到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。
sentinel中一般冷启动的过程系统容许经过的 QPS 曲线以下图所示:
冷启动的两种模式,令牌桶和漏斗大同小异,只不过在流量较大时,冷启动过程 令牌桶走势相似于阶梯向上直到设定的限流值,漏洞走势相似于几个斜线向上之道设定的限流值。
关于sentinel更多的知识可参考官方文档:https://sentinelguard.io/zh-cn/docs/introduction.html
推荐阅读