限流方式、算法、策略、位置

为什么要限流?

限流是为了保护系统的稳定性和可靠性,防止系统因过载而崩溃或性能下降

  • 防止系统资源过度消耗:限流可以限制并发请求的数量,防止系统资源被过度消耗。如果系统无限制地处理请求,可能导致系统资源(CPU\内存\数据库连接等)耗尽,使系统无法正常响应。
  • 保护后端服务:限流可以保护后端服务免受突发地高负载请求的影响。当大量请求同时涌入时,如果没有限流措施,后端服务可能会因为无法承受高并发而崩溃。
  • 提高系统稳定性和可靠性:限流可以平滑请求的流量,避免系统出现过载和雪崩效应。通过合理的限流策略,可以保持系统在可接受的负载范围内运行,提高系统的稳定性和可靠性。
  • 用户体验优化:限流可以避免因大量请求同时到达而导致的响应延迟增加,保证用户请求的快速响应,提升用户体验。

限流方式

  • 基于请求限流
  • 基于资源限流

基于请求限流

基于请求限流指从外部访问的请求角度考虑限流,常见方式有两种

  • 限制总量,也就是限制某个指标的累积上限,常见的是限制当前系统服务的用户总量,例如:某个直播间限制总用户数上限为100万,超过100万后新的用户无法进入;某个抢购活动商品数量只有100个,限制参与抢购的用户上限为1万个,一万以后的用户直接拒绝。
  • 限制时间。限制一段时间内某个指标的上限。

缺点:

  • 实践中面临的主要问题是比较难以找到合适的阈值,例如系统设定了1分钟10000个用户,但实际上6000个用户的时候系统就扛不住了;或者达到1分钟10000用户后,其实系统压力还不大,但此时已经开始丢弃用户访问了。而且还要考虑硬件相关的因素,例如一台32核的机器和64核的机器处理能力差别很大,阈值不同。

应用:

-适用于业务功能比较简单的系统,例如负载均衡系统、网关系统、抢购系统等


基于资源限流

基于资源限流是从系统内部考虑的,也就是找到系统内部影响性能的关键资源,对其使用上限进行限制。常见的内部资源包括连接数,文件句柄,线程数和请求队列等。比如CPU的占用率超过80%的时候拒绝新的请求。
优点

  • 有效反映当前系统压力,更好进行限流
    缺点:
  • 难以确定关键资源,
  • 难以确定关键资源的阈值,需在线上逐步调式,持续观察,直到找到合适的值。

应用:

  • 适用于具体的某个服务,比如订单系统,商品系统

限流算法

一些常见的限流算法有:

  • 计数器
  • 滑动窗口
  • 漏桶
  • 令牌桶

计数器[固定窗口计数]

计数器算法就是通过计数记录请求次数。先设定一个单位时间的请求上限[阈值],要求单位时间内的请求量不得超过这个阈值。单位时间内,每来一个请求加1达到上限就拒绝服务,过了单位时间就重新计时。[单位时间就是固定窗口,假设单位时间是1min,那么固定窗口就是1min-2min,我们只需要考虑当前时间所在的窗口即可,下一个窗口重新计数。]
具体实现中,单机限流可以用一个整数+时间戳记录。时间戳达到上限计数器从0开始计数,计数达到上限,拒绝服务。
分布式限流,可以使用redis来做,redis有天然的过期时间,过期就重新计数。[用LUA保证操作的原子性]
优点:

  • 简单直观,易于理解和实现
    缺点:
  • 存在临界点问题;假设1min内的阈值为100,比如用户在[0.5,1]这段区间访问了100次,用户在[1,1.5]这段区间访问了100次,在各自的窗口内都没有超过阈值上限,但是在[0.5,1.5]这1min内用户访问了200次超过了阈值上限。
    在这里插入图片描述

滑动窗口

为了解决"固定窗口"临界点的问题,引入了"滑动窗口"。
固定窗口之所以出现"临界点"的问题是只考虑当前时间所在的窗口,窗口向前移动的时隙大。

滑动窗口。就是以当前的时间点为基准将时间窗口向前移动,窗口的起始和截止边界是随着时间变化的,但是窗口的长度是不变的。这样就解决了"临界点"的问题。
在这里插入图片描述
具体实现:
利用redis的zset[依据访问时间进行排序]实现,key记录用户的请求,score记录请求的时间。
可以把"用户访问的时间点"作为滑动窗口的右边界,根据窗口的长度计算出窗口的左边界,利用zcount keyname min max计算出时间戳在[min,max]区间的请求数量,以此来判断是否达到请求上限。
优点:

  • 解决了"固定窗口"算法的"临界点"问题。
    缺点:

  • 相对于"固定窗口"复杂度提升。

  • 依然存在"临界点"问题只是发生概率比较小。滑动窗口只是以更小的时隙移动区间,假设固定窗口是以1min为单位移动区间的,滑动窗口就可能是以1s为单位移动的,后者出现的临界问题概率更小,但是依然可能出现。

窗口问题总结
窗口临界问题就是,在窗口即将被移动的时候,请求量达到阈值,窗口向前移动重新计数,此时窗口的起始请求量达到了阈值,那么就会在一个窗口长度的区间内请求量超过上限。

漏桶

  • 漏桶相当于一个速率恒定器,强制限制数据的流出[输出]速率。
  • 漏桶的容量是固定的,漏桶的数据流入速率不定[可大可小],但是漏桶的数据流出速率恒定,业务的核心逻辑线程会从漏桶的"出水口"处获取待处理的请求。
  • 如果漏桶的数据流出速率远大于数据流入速率,那么到来的请求能够以较快的速度被处理;但是数据流出的速率远小于数据的流入速率,那么会有一些来不及处理的请求被存储在漏桶中,但是由于漏桶容量有限,存储的请求也有限,桶满之后新到来的请求会被丢弃。
  • 由于数据的输出速率是限死的所以没办法更好地应对突发流量。

在这里插入图片描述
概念

  • 漏桶容量为C
  • 数据的到达速率p
  • 数据的最大输出速率r
  • 则数据的最大突发时间长度S= C/(r-p)

具体实现:
可以用一个带有容量的队列[链表,数组],业务逻辑线程以恒定的频率从队头获取请求,新到来的请求在队列未满的情况下从队尾加入队列。

缺点:

  • 可以平滑流量但是无法解决流量突增的问题
  • 无法将服务的处理能力发挥到极致。由于网络状态和后端服务的处理能力是随时变化的,刚开始漏桶数据输出速率是一个很小的值,如果此时来了一波比较大的流量并且后端服务有一定的能力能够处理这波流量,但是由于数据的流出速率是恒定的,所以只能丢弃掉这波请求。
    解决方式:1.随时变动数据的流出速率,通过对后端不断进行试探,尽可能将后端性能发挥到极致。弊端就是带来了更多的复杂性。2.令牌桶

令牌桶

也是有一个固定大小的桶,但是桶内装的不是待处理的数据,而是"令牌"[先有令牌才能处理数据]。

  • 数据的输出必须持有令牌
  • 令牌的产生的速率是恒定的,如果令牌没有及时被使用可以存储在令牌桶内,桶满则被丢弃
  • 突发数据达到时,令牌桶内有多个令牌,突发数据可以持有令牌被输出

令牌桶之所以能够应对"突发流量",是因为令牌桶在没有请求到来的时候可以在桶中累积"令牌",那么有突发流量来临的时候,由于已经积累了足够的"令牌"所以能更好的应对这波流量。
假设漏桶的数据流出速率是200Mbps,令牌桶的容量是400M,令牌到达速率为200Mbps,第一波流量是100Mbps此时漏桶和令牌桶都能够应对。并且令牌桶中还累积了100M的令牌。第二波流量是300Mbps,对于漏桶只能丢弃100Mbps的数据,而令牌桶就可以很好地应对。
在这里插入图片描述
概念

  • burst length S sec 突发时间
  • token bucket capacity B bytes令牌桶中当前的令牌数
  • token arrival rate R bytes/sec 令牌到达速率
  • maximum output rate M bytes/sec 最大输出的速度 [突发速度]
  • 有公式MS = B+RS

以下是有关令牌桶的两道例题:
1.在10Mbps[突发速度]的网络上,一台主机通过令牌桶进行流量整形,令牌的到达速率为2Mbps,初始时,令牌被填充到6Mbits的容量,计算该主机发送40Mbits数据需要的时间。
在这里插入图片描述

2.假设路由器使用令牌桶算法对数据进行存储转发,路由器输入队列的最大容量为2.4MB,令牌到达的速率为0.5Mbps,每个令牌允许路由器发送一个字节数据,路由器允许的最大输出速率为5Mbps。从某时刻开始数据以恒定速率10Mbps进入路由器,此时刻令牌桶中的令牌个数为0.45M。试求出哪个时间点路由器输入队列达到最大值。
在这里插入图片描述

漏桶 VS 令牌桶

  • 漏桶里面装的是待处理的请求,而令牌桶里面装的是处理请求前需要先获取的令牌[有令牌可以立即处理请求]
  • 漏桶满丢弃的是请求,令牌桶满丢弃的是令牌
  • 漏桶无法解决流量突增的问题,令牌桶可以解决流量突增的问题

限流策略

  • 服务拒绝。当请求流量达到限流阈值时,对多余的请求直接拒绝。
  • 延时处理。通过将多余的请求加入缓存队列或延时队列,应对短期的流量突增,高峰期过后开始将堆积的请求流量逐个处理。
  • 请求分级[优先级]。对不同来源的请求设置优先级,先处理优先级更高的请求。
  • 动态限流。可以监控系统相关指标,评估系统压力,通过注册中心,配置中心等动态调整限流阈值。
  • 监控预警和动态扩容。如果有优秀的服务监控系统与自动部署,发布系统,可以通过监控系统自动监测系统运行情况,对短期内服务压力暴增,流量大幅度写入的情况进行邮件。短信等方式进行预警。

限流位置

  • 接入层限流。可以通过API路由网关等对域名或IP进行限流,同时可以拦截非法请求。
  • 应用限流。每个服务可以有自己的单机或者集群限流措施,也可以调用第三方服务的限流服务。
  • 基础服务限流。数据库:限制数据库连接;消息队列:限制消费速率

总结

限流虽然会导致部分用户的部分请求丢失,但是在更大程度上保证了系统的安全性和稳定性。以上四种算法针对的是单体框架的限流策略。对于分布式,微服务系统来说,可以借用一些中间件或者网关配置相应的限流策略

参考文章

1.服务器负载过高,请求过多导致应用崩溃
2.服务限流
3.redis高级应用场景
4.分布式限流实现方案

相关推荐

  1. 算法学习

    2023-12-23 16:16:01       14 阅读
  2. 四种算法

    2023-12-23 16:16:01       41 阅读
  3. RateLimiter 算法使用

    2023-12-23 16:16:01       9 阅读
  4. golang版本使用令牌桶算法来实现策略

    2023-12-23 16:16:01       35 阅读
  5. 服务实现方案

    2023-12-23 16:16:01       34 阅读

最近更新

  1. TCP协议是安全的吗?

    2023-12-23 16:16:01       19 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-23 16:16:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-23 16:16:01       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-23 16:16:01       20 阅读

热门阅读

  1. Python的内存管理与垃圾回收机制

    2023-12-23 16:16:01       39 阅读
  2. web服务以Jetty作为伺服器并以docker打镜像部署

    2023-12-23 16:16:01       37 阅读
  3. Hive的四种排序方法

    2023-12-23 16:16:01       37 阅读
  4. 第二百二十二回

    2023-12-23 16:16:01       42 阅读
  5. Spring Boot 定时任务实现

    2023-12-23 16:16:01       39 阅读