固定窗口 滑动窗口
限流算法主要用于限制系统的请求流量,以防止系统因超载而崩溃。
这些算法在高并发场景下具有广泛的应用,包括但不限于以下几个具体场景:
- 微服务:在微服务架构中,服务之间的调用非常频繁。为了确保每个服务都能稳定运行,可以使用限流算法来控制服务之间的调用频率,防止某个服务被过多的请求压垮。
- API网关:API网关是连接客户端和内部服务的重要桥梁。为了保护内部服务不受恶意攻击或过载请求的影响,API网关通常会使用限流算法来限制请求速率。
- 数据库保护:数据库是系统的核心组件之一,其性能直接影响整个系统的稳定性。为了防止数据库被过多的查询请求压垮,可以使用限流算法来限制对数据库的访问频率。例如,漏桶算法可以将对数据库的访问请求加入到木桶中,再以数据库能够承受的查询速率(QPS)从木桶中取出请求进行处理。
- 缓存:在高并发场景下,缓存可以显著提高系统的响应速度。然而,如果缓存被过多的请求压垮,反而会导致系统性能下降。因此,可以使用限流算法来控制对缓存的访问频率,确保缓存能够稳定运行。
- 电商抢购:在电商抢购等场景中,用户请求量会在短时间内激增。为了应对这种突发流量,可以使用令牌桶算法等限流算法来平滑处理请求,确保系统能够处理尽可能多的请求,同时避免系统崩溃。
- 热点事件处理:在社交媒体等平台上,热点事件往往会引发大量的用户关注和讨论。这会导致系统在短时间内受到大量的请求。通过使用限流算法,可以确保系统能够平稳处理这些请求,避免服务器过载。
综上所述,限流算法在高并发场景下具有广泛的应用价值,可以保护系统免受过载请求的影响,提高系统的稳定性和可用性。在实际应用中,需要根据具体场景选择合适的限流算法,并合理配置参数以达到最佳效果。
固定窗口
简单来说: 就是我们规定, 在一定的时间周期内, 我们只响应一定数量的请求, 多了就拒绝.
固定窗口又称固定窗口(又称计数器算法,Fixed Window)限流算法,是最简单的限流算法,通过在单位时间内维护的计数器来控制该时间单位内的最大访问量。
假设限制每分钟请求量不超过60,设置一个计数器,当请求到达时如果计数器到达阈值,则拒绝请求,否则计数器加
固定窗口最大的优点在于易于实现;并且**内存占用小*.
我们只需要存储时间窗口中的计数即可;它能够确保处理更多的最新请求,不会因为旧请求的堆积导致新请求被饿死。当然也面临着临界问题,当两个窗口交界处,瞬时流量可能为2n。
滑动窗口
为了防止瞬时流量,可以把固定窗口近一步划分成多个格子,每次向后移动一小格,而不是固定窗口大小,这就是滑动窗口(Sliding Window)。
比如每分钟可以分为6个10秒中的单元格,每个格子中分别维护一个计数器,窗口每次向前滑动一个单元格。每当请求到达时,只要窗口中所有单元格的计数总和不超过阈值都可以放行。TCP协议中数据包的传输,同样也是采用滑动窗口来进行流量控制。
漏桶限流算法(漏了一个洞的桶)
如何更加平滑的限流?不妨看看漏桶算法(Leaky Bucket),请求就像水一样以任意速度注入漏桶,而桶会按照固定的速率将水漏掉;当注入速度持续大于漏出的速度时,漏桶会变满,此时新进入的请求将会被丢弃。限流和整形是漏桶算法的两个核心能力。
漏桶算法存在目的主要是用来平滑突发的流量,提供一种机制来确保网络中的突发流量被整合成平滑稳定的额流量。
不过由于漏桶对流量的控制过于严格,在有些场景下不能充分使用系统资源,因为漏桶的漏出速率是固定的,即使在某一时刻下游能够处理更大的流量,漏桶也不允许突发流量通过。
令牌桶
如何在够限制流量速率的前提下,又能够允许突发流量呢?令牌桶算法了解一下!令牌桶算法是以恒定速率.
令牌桶具有以下特点:
- 以恒定的速率发放令牌,假设限流速率为v/s,则表示每1/v秒发放一个令牌
- 假设令牌桶容量是b,如果令牌桶已满,则新的令牌会被丢弃
- 请求能够通过限流器的前提是令牌桶中有令牌
令牌桶算法中值得关注的参数有两个,即限流速率v/s,和令牌桶容量b;速率a表示限流器一般情况下的限流速率,而b则是burst的简写,表示限流器允许的最大突发流量。
比如b=10,当令牌桶满的时候有10个可用令牌,此时允许10个请求同时通过限流器(允许流量一定程度的突发),这10个请求瞬间消耗完令牌后,后续的流量只能按照速率r通过限流器。
分布式限流
以上几种限流算法的实现都仅适合[单机限流]。
虽然给每台机器平均分配限流配额可以达到限流的目的,但是由于机器性能,流量分布不均以及计算数量动态变化等问题,单机限流在分布式场景中的效果总是差强人意。
分布式限流最简单的实现就是利用中心化存储,即将单机限流存储在本地的数据存储到同一个存储空间中,如常见的Redis等。
总结
-
固定窗口算法实现简单,性能高,但是会有临界突发流量问题,瞬时流量最大可以达到阈值的2倍。
-
为了解决临界突发流量,可以将窗口划分为多个更细粒度的单元,每次窗口向右移动一个单元,于是便有了滑动窗口算法。
滑动窗口当流量到达阈值时会瞬间掐断流量,所以导致流量不够平滑。
-
想要达到限流的目的,又不会掐断流量,使得流量更加平滑?可以考虑漏桶算法!需要注意的是,漏桶算法通常配置一个FIFO的队列使用以达到允许限流的作用。
由于速率固定,即使在某个时刻下游处理能力过剩,也不能得到很好的利用,这是漏桶算法的一个短板。
-
限流和瞬时流量其实并不矛盾,在大多数场景中,短时间突发流量系统是完全可以接受的。令牌桶算法就是不二之选了,令牌桶以固定的速率v产生令牌放入一个固定容量为n的桶中,当请求到达时尝试从桶中获取令牌。
当桶满时,允许最大瞬时流量为n;当桶中没有剩余流量时则限流速率最低,为令牌生成的速率v。
-
如何实现更加灵活的多级限流呢?滑动日志限流算法了解一下!这里的日志则是请求的时间戳,通过计算制定时间段内请求总数来实现灵活的限流。
当然,由于需要存储时间戳信息,其占用的存储空间要比其他限流算法要大得多。
不管黑猫白猫,能抓到老鼠的就是好猫。限流算法并没有绝对的好劣之分,如何选择合适的限流算法呢?不妨从性能,是否允许超出阈值,落地成本,流量平滑度,是否允许突发流量以及系统资源大小限制多方面考虑。
当然,市面上也有比较成熟的限流工具和框架。如Google出品的Guava中基于令牌桶实现的限流组件,拿来即用;以及alibaba开源的面向分布式服务架构的流量控制框架Sentinel更会让你爱不释手,它是基于滑动窗口实现的。「本文代码地址」