深入解析分布式限流

一、概述

1.1 主要解决的问题

  1. 访问请求流量远远大于服务器的负载,致使服务器宕机,导致整个服务的不可用;- 限流
  2. 当前服务调用其他服务,其他服务不可用,导致当前服务的调用一直超时,进而当前服务的线程资源耗尽,进而服务宕机,产生服务雪崩。- 服务熔断【或降级】

1.2 限流定义

通过限制并发数或一段时间窗口允许处理的最大连接数来保护系统,一旦超过设定阈值,对当前请求进行处理。主要的处理方式有:跳转到错误页面、进入排队系统或降级等。本质上,就是损失一部分用户的可用性,来保证整体的可用性

1.3 常见限流规则

1. QPS或连接数控制;例如对单个IP的限制、单台机器的限制、单个服务组的限制或整个机房的限制
2. 传输速率:例如资源的下载速度
3. 黑白名单。

1.4 分布式限流

把整个分布式环境中所有服务器当做一个整体来考量。比如说针对IP的限流,我们限制了1个IP每秒最多10个访问,不管来自这个IP的请求落在了哪台机器上,只要是访问了集群中的服务节点,那么都会受到限流规则的制约。必须将限流信息保存在一个中心化的组件上,这样它就可以获取到集群中所有机器的访问状态,目前有两个比较主流的限流方案:

  1. 网关层限流:应用在流量入口处;
  2. 中间件限流:将限流信息存储在分布式环境中某个中间件里(比如Redis缓存),每个组件都可以从这里获取到当前时刻的流量统计,从而决定是拒绝服务还是放行流量。

二、常用的限流方案

在这里插入图片描述

2.1 Guava限流

一种Google研发的客户端限流组件,非常轻量级。但仅支持单机限流。底层是令牌桶限流算法

2.2 网关层限流

将系统流量的分布层次抽象成一个简单的漏斗模型来看。
在这里插入图片描述
上面是一个最普通的流量模型,从上到下的路径依次是:

  1. 用户流量从网关层转发到后台服务
  2. 后台服务承接流量,调用缓存获取数据
  3. 缓存中无数据,则访问数据库

Nginx限流

  1. 基于IP地址和基于服务器的访问请求限流
  2. 并发量(连接数)限流
  3. 下行带宽速率限制

SpringCloud 的GateWay组件限流。

2.3 中间件限流

方案1: Redis+LUA脚本实现限流:
方案2: Sentinal限流:底层使用滑动窗口算法来限流。

三、常用限流算法

3.1 计数器限流

概述:在一定周期内累加访问次数,当访问次数达到阈值时,触发限流策略,当进入下一个时间周期时,计算器会清零,重新计数。
适用场景:短信发送次数限制
存在问题:临界问题,会造成系统的抖动。假设时间周期为1s,阈值为50。开始时间是32s, 32.0-32.8s请求次数为10,32.8-33s请求次数为30,33.0-33.2请求次数为30,33.3-34s请求次数为30,可以看出在32s和33s时间窗口内都没有触发限流阈值,但在32.8-33.2区间内超过限流阈值,造成系统的不稳定。

3.2 滑动窗口限流

概述:解决了计数器限流算法的临界问题。将固定周期划分为n个小的时间段,分别在每个时间段内统计请求访问次数,然后根据时间将窗口向前滑动并删除过期的时间段,时间段越短统计的越准,很好的解决了临界问题
适用场景:sentinel底层采用该算法
存在问题:窗口大小选择以及n大小的选择。

3.3 令牌桶限流

概述:对于每一个请求,都需要先从令牌桶中获取令牌。若获取不到令牌,触发限流策略。系统会以一个恒定速率向令牌童中放入令牌,令牌中满了后直接丢弃令牌
适用场景:网络流量整形和速率限制,适合处理突发流量。当突发流量来的时候,可以直接获取令牌中所有的令牌进行快速处理。Guava底层就采用该算法
存在问题:虽然可以处理突发流量,但后台系统的压力也会瞬间增大,要合理设置令牌数量。

3.4 漏桶限流算法

概述控制数据注入网络的速度。在漏桶内部维护一个容器,这个容器会以恒定速率出水,不论漏桶的流入速度多快,出水的速度是固定的,消息中间件就利用了该思想。
适用场景:流量平滑
存在的问题:无法处理突发流量。漏桶的天然特性决定了它不会发生突发流量,就算每秒1000个请求到来,那么它对后台服务输出的访问速率永远恒定。而令牌桶则不同,其特性可以预存一定量的令牌,因此在应对突发流量的时候可以在短时间消耗所有令牌,其突发流量处理效率会比漏桶高,但是导向后台系统的压力也会相应增多。

四、Guava流量预热

4.1 概述

核心思想:动态的调整令牌的发放速度,让流量变化更加平滑。例如:某个接口设定了100个Request每秒的限流标准,同时使用令牌桶算法做限流。假如当前时间窗口内都没有Request过来,那么令牌桶中会装满100个令牌。如果在下一秒突然涌入100个请求,这些请求会迅速消耗令牌,对服务的瞬时冲击会比较大。

4.2 预热模型

在这里插入图片描述

其中横坐标是令牌桶的当前容量,纵坐标是令牌发放速率。

闲时到忙时的流量转变:假定当前我们处于闲时流量阶段,没几个访问请求,这时令牌桶是满的。接着在下一秒突然涌入了10个请求,这些请求开始消耗令牌桶中的令牌。在初始阶段,令牌的放行速度比较慢,在第一个令牌被消耗以后,后面的请求要经过3x时间间隔也就是0.3s才会获取第二块令牌。随着令牌桶中令牌数量被逐渐消耗,当令牌存量下降到最大容量一半的时候(Half位置),令牌放行的速率也会提升,以稳定间隔0.1s发放令牌。
流量从忙时转变为闲时:令牌发放速率是由快到慢逐渐变化。起始阶段的令牌放行间隔是0.1s,随着令牌桶内令牌逐渐增多,当令牌的存量积累到最大容量的一半后,放行令牌的时间间隔进一步增大为0.3s。

RateLimiter正是通过这种方式来控制令牌发放的时间间隔,从而使流量的变化更加平滑。

五、Sentinel工作原理

概述:一款高性能的分布式限流组件,能够保护微服务架构下的应用程序,实现服务限流和服务降级熔断等。
主要原理:利用AOP切面来拦截所有的请求,对请求进行实时计数、实时统计等,并根据设定的阈值来决定是否放行该请求。
主要流程为:

1. 规则配置。利用sentinel提供的功能来配置限流规则,即每分钟请求的次数。限流规则会被加载到内存中,sentinel会利用这些限流规则进行限流
2. 请求拦截。在程序处理处理之前,sentinel利用AOP切面拦截所有的请求;
3. 统计请求。拦截后,sentinel会对请求进行实时统计,在内存中维护的时间窗口内统计请求qps,响应时间以及异常次数等;
4. 判断流量。如果qps超过设定的阈值,则进行限流处理,包括降级等;若调用其他服务的响应时间或异常次数超过阈值,则直接熔断服务,不再调用其他服务,返回一个默认的降级值
5. 动态调整限流。可以在运行期间,sentinel可以修改阈值,删除规则等

相关推荐

  1. 【微服务】分布式如何实现

    2024-03-20 12:16:03       65 阅读
  2. Springboot Redis Lua 分布式

    2024-03-20 12:16:03       71 阅读
  3. 分布式系统接口方案

    2024-03-20 12:16:03       31 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-20 12:16:03       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-20 12:16:03       106 阅读
  3. 在Django里面运行非项目文件

    2024-03-20 12:16:03       87 阅读
  4. Python语言-面向对象

    2024-03-20 12:16:03       96 阅读

热门阅读

  1. 一、初始项目服务拆分和远程调用

    2024-03-20 12:16:03       37 阅读
  2. 24.3 分布式综合应用

    2024-03-20 12:16:03       31 阅读
  3. R语言系列6——R语言中的机器学习入门

    2024-03-20 12:16:03       34 阅读
  4. 阿里云2025届春招实习生招聘

    2024-03-20 12:16:03       43 阅读
  5. 阿里云MongoDB 分片集群介绍

    2024-03-20 12:16:03       43 阅读
  6. 基于单片机的霓虹灯控制系统设计

    2024-03-20 12:16:03       41 阅读
  7. 洛谷 P1019 [NOIP2000 提高组] 单词接龙

    2024-03-20 12:16:03       41 阅读
  8. web学习笔记(三十八)

    2024-03-20 12:16:03       41 阅读
  9. 深入剖析Apache Kafka Partition:结构、策略与影响

    2024-03-20 12:16:03       41 阅读
  10. 【力扣】26.删除有序数组中的重复项

    2024-03-20 12:16:03       36 阅读