一、为什么要限流?
生活场景:
比如,周末去饭店吃饭,但是人太多了,只能去前台拿个号,等服务员叫到号的时候才能进饭店吃饭。如果饭店没有限流怎么办?一到饭点,人都往里冲,而饭店又处理不了这么多人流,很容易就出事故(饭店塞满了人,无路可走。饭店的工作人员崩溃了,处理不过来)
代码世界:
1、大量正常用户高频访问导致服务器宕机
2、恶意用户高频访问导致服务器宕机
3、网页爬虫,对于这些情况我们需要对用户的访问进行限流访问
典型场景:
1.电商系统商品秒杀
2.12306火车票系统
二、限流的算法有哪些?
1. 令牌桶算法
1)所有的请求在处理之前都需要拿到一个可用的令牌才会被处理;
2)根据限流大小,设置按照一定的速率往桶里添加令牌;
3)桶设置最大的令牌限制,当桶满时、新添加的令牌就被丢弃或者拒绝;
4)请求达到后首先要获取令牌桶中的令牌,拿着令牌才可以进行其他的业务逻辑,处理完业务逻辑之后,将令牌直接删除;
5)令牌桶有最低限额,当桶中的令牌达到最低限额的时候,请求处理完之后将不会删除令牌,以此保证足够的限流;
2.漏桶算法
1)漏桶则是按照常量固定速率流出请求,流入请求速率任意,当流入的请求数累积到漏桶容量时,则新流入的请求被拒绝
2)漏桶限制的是常量流出速率(即流出速率是一个固定常量值,比如都是1的速率流出,而不能一次是1,下次又是2),从而平滑突发流入速率;
3. 固定窗口算法
首先维护一个计数器,将单位时间段当做一个窗口,计数器记录这个窗口接收请求的次数。
当次数少于限流阀值,就允许访问,并且计数器+1
当次数大于限流阀值,就拒绝访问。
当前的时间窗口过去之后,计数器清零。
假设单位时间是1秒,限流阀值为3。在单位时间1秒内,每来一个请求,计数器就加1,如果计数器累加的次数超过限流阀值3,后续的请求全部拒绝。等到1s结束后,计数器清0,重新开始计数。
这个时候看起来没有什么问题,但事实总是残酷的!
1. 一段时间内(不超过时间窗口)系统服务不可用。比如窗口大小为1s,限流大小为100,然后恰好在某个窗口的第1ms来了100个请求,然后第2ms-999ms的请求就都会被拒绝,这段时间用户会感觉系统服务不可用。
2. 窗口切换时可能会产生两倍于阈值流量的请求。假设限流阀值为5个请求,单位时间窗口是1s,如果我们在单位时间内的前0.8-1s和1-1.2s,分别并发5个请求。虽然都没有超过阀值,但是如果算0.8-1.2s,则并发数高达10,已经超过单位时间1s不超过5阀值的定义啦,通过的请求达到了阈值的两倍
为了解决这个问题引入了滑动窗口限流。
4.滑动窗口算法
滑动窗口可以简单理解为,设定的单位时间就是一个窗口,窗口可以分割多个更小的时间单元,随着时间的推移,窗口会向右移动。比如一个接口一分钟限制调用1000次,1分钟就可以理解为一个窗口,可以把1分钟分割为10个单元格,每个单元格就是6秒。当滑动窗口的格子划分的越多,滑动窗口滚动的就越平滑,限流的统计就会越精确
最简单的限流算法就是计数限流了,例如系统能同时处理100个请求,保存一个计数器,处理了一个请求,计数器加一,一个请求处理完毕之后计数器减一。
每次请求来的时候看看计数器的值,如果超过阈值要么拒绝。
非常的简单粗暴,计数器的值要是存内存中就算单机限流算法。存中心存储里,例如 Redis 中,集群机器访问就算分布式限流算法。
优点:简单粗暴,单机在 Java 中可用 Atomic 等原子类、分布式就 Redis incr。
缺点:假设我们允许的阈值是1万,此时计数器的值为0, 当1万个请求在前1秒内一股脑儿的都涌进来,这突发的流量可是顶不住的。缓缓的增加处理和一下子涌入对于程序来说是不一样的。
Sentinel简介
Sentinel是阿里开源的项目,提供了流量控制、熔断降级、系统负载保护等多个维度来保障服务之间的稳定性。
丰富的应用场景: 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
完备的实时监控: 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
广泛的开源生态: 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入Sentinel。
完善的SPI扩展点: 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快
速地定制逻辑。例如定制规则管理、适配动态数据源等。
生态圈
特性
Sentien流控模式
1.QPS & Thread
流量控制(Flow Control),原理是监控应用流量的QPS或并发线程数等指标,当达到指定阈值时对流量进行控制,避免系统被瞬时的流量高峰冲垮,保障应用高可用性。
基本参数:
资源名:唯一名称,默认请求路径
针对来源:可以针对调用者进行限流,填写微服务名,默认为default(不区分来源)
阈值类型/单机阈值:
1.QPS:每秒请求数,当前调用该api的QPS到达阈值的时候进行限流
2.线程数:当调用该api的线程数到达阈值的时候,进行限流
应用场景:
QPS:电商系统秒杀,比喻秒杀可用库存100,同一时刻预估有5W请求进来,可以采用QPS的方式直接拒绝大部分请求,留下500个请求进来走到业务逻辑,其余请求直接返回已售完。
Thread:比喻一个服务可承受的并发线程数100,可以针对线程数峰值合理分配到不同的资源。(同一个服务需要针对不同的业务逻辑使用不同的线程池来做隔离,避免业务自身之间的资源争抢)。
2.关联模式
调用关系包括调用方、被调用方;一个方法又可能会调用其它方法,形成一个调用链路的层次关系。Sentinel 通过 NodeSelectorSlot 建立不同资源间的调用的关系,并且通过 ClusterBuilderSlot 记录每个资源的实时统计信息。
当两个资源之间具有资源争抢或者依赖关系的时候,这两个资源便具有了关联。
比如对数据库同一个字段的读操作和写操作存在争抢,读的速度过高会影响写得速度,写的速度过高会影响读的速度。如果放任读写操作争抢资源,则争抢本身带来的开销会降低整体的吞吐量。可使用关联限流来避免具有关联关系的资源之间过度的争抢.
应用场景:
查询订单接口,批量查询订单然后对订单进行更新,查询接口关联更新接口,当更新接口达到阀值时,开启查询接口限流,为更新接口让出更多服务器资源
3.预热 & 排队模式
预热 - 令牌桶算法:根据codeFactor(冷加载因子,默认为3)的值,即请求 QPS 从 threshold / 3 开始,经预热时长逐渐升至设定的 QPS 阈值 ,这种情况主要是为了保护系统,例如在秒杀系统的开启瞬间,会有很多流量上来,很可能会把系统打挂,预热方式就是为了保护系统,可以慢慢的把流量放进来,慢慢的把阈值增长到设定值。
排队 - 漏桶算法:某瞬时来了大流量的请求, 而如果此时要处理所有请求,很可能会导致系统负载过高,影响稳定性。但其实可能后面几秒之内都没有消息投递,若直接把多余的消息丢掉则没有充分利用系统处理消息的能力。排队模式会以固定间隔通过请求,如果请求超过阀值则排队,排队时间超过了设置的超时时间,则限流。
4.热点 & 授权
何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:
商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制
热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
授权:
很多时候,我们需要根据调用方来限制资源是否通过,这时候可以使用 Sentinel 的访问控制(黑白名单)的功能。黑白名单根据资源的请求来源(origin)限制资源是否通过,若配置白名单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。
插槽Slot
slot是sentinel中非常重要的概念,sentinel的工作流程就是围绕着一个个插槽所组成的插槽链来展开的。需要注意的是每个插槽都有自己的职责,他们各司其职完好的配合,通过一定的编排顺序,来达到最终的限流降级的目的。默认的各个插槽之间的顺序是固定的,因为有的插槽需要依赖其他的插槽计算出来的结果才能进行工作。
但是这并不意味着我们只能按照框架的定义来,sentinel 通过 SlotChainBuilder 作为 SPI 接口,使得 Slot Chain 具备了扩展的能力。我们可以通过实现 SlotsChainBuilder 接口加入自定义的 slot 并自定义编排各个 slot 之间的顺序,从而可以给 sentinel 添加自定义的功能。
Slot功能职责
NodeSelectorSlot 负责收集资源的路径,并将这些资源的调用路径,以树状结构存储起来,用于根据调用路径来限流降级;
ClusterBuilderSlot 用于存储资源的统计信息以及调用者信息,例如该资源的 RT, QPS, thread count 等等,这些信 息将用作为多维度限流,降级的依据;
LogSlot 用于记录用于记录块异常,为故障排除提供具体的日志
StatisticsSlot 用于记录,统计不同维度的 runtime 信息;
SystemSlot 根据当前系统的整体情况,对入口资源的调用进行动态调配。其原理是让入口的流量和当前系统的预计容量达到一个动态平衡。
AuthoritySlot 则根据黑白名单,来做黑白名单控制;
FlowSlot 则用于根据预设的限流规则,以及前面 slot 统计的状态,来进行限流;
DegradeSlot 则通过统计信息,以及预设的规则,来做熔断降级;
Slot责任链
每个Slot执行完业务逻辑处理后,会调用fireEntry()方法,该方法将会触发下一个节点的entry方法,下一个节点又会调用他的fireEntry,以此类推直到最后一个Slot,由此就形成了sentinel的责任链。
开发测试(原始模式)
Sentinel控制台通过 API 将规则推送至客户端并直接更新到内存中。这种情况下应用重启规则就会消失,仅用于简单测试。
生产(push模式)
Sentinel Dashboard作为server client与配置中心交互,将规则推送并保存到配置中心,sentinel客户端实时监听配置中心的变化,获取最新规则。