Gateway 限流及令牌桶算法源码分析

本文介绍了Spring Cloud Gateway限流的重要性,详细阐述了Gateway的工作流程和常见限流方法,重点讨论了令牌桶算法,包括其原理、优缺点,并提供了源码分析,展示了如何在Java中实现限流,以及使用KeyResolver和yaml配置限流。通过JMeter进行压测验证了限流效果。

1.为什么需要限流

1、大量正常用户高频访问导致服务器宕机
2、恶意用户高频访问导致服务器宕机
3、网页爬虫 ,对于这些情况我们需要对用户的访问进行限流访问

限流的目的是通过对并发访问/请求进行限速,或者对一个时间窗口内的请求进行限速来保护系统,一旦达到限制速率则可以拒绝服务、排队或等待、降级等处理。

2.Gateway在哪里可以实现限流

2.1Gateway 相关概念

Spring Cloud Gateway 是 Spring 官方基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,Spring Cloud Gateway 旨在为微服务架构提供一种简单而有效的统一的API路由管理方式。Spring Cloud Gateway 作为Spring Cloud 生态系中的网关,目标是替代 Zuul,其不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/埋点,和限流等。Spring Cloud Gateway 可以看做是一个 Zuul 1.x 的升级版和代替品,比 Zuul 2 更早的使用 Netty 实现异步 IO,从而实现了一个简单、比 Zuul 1.x 更高效的、与 Spring Cloud 紧密配合的 API 网关。

Spring Cloud Gateway 里明确的区分了 Router 和 Filter,并且一个很大的特点是内置了非常多的开箱即用功能,并且都可以通过 SpringBoot 配置或者手工编码链式调用来使用。比如内置了 10 种 Router,使得我们可以直接配置一下就可以随心所欲的根据 Header、或者 Path、或者 Host、或者 Query 来做路由。比如区分了一般的 Filter 和全局 Filter,内置了 20 种 Filter 和 9 种全局 Filter,也都可以直接用。当然自定义 Filter 也非常方便。

  • Route: 网关基本构建块,由一个 ID、一个目标 URI,一组 predicate 和一组 filter 定义,若 predicate 为真,则路由匹配。
  • Predicate:输入类型是一个 ServerWebExchange,可以使用它来匹配来自 HTTP 请求的任何内容。
  • Filter:Gateway 中分为两种 filter,一个是 Gateway Filter 一个是 Global Filter,filter 会对请求和响应进行修改处理。

2.2Gateway 工作流程

客户端访问 Gateway 网关,Gateway 中 Handler Mapping 对请求 URL 进行处理,如果网关处理程序映射确定请求与路由匹配,则处理完之后交给 web Handler,web handler 会被 filter 进行过滤。Filter 中分成两部分,以在代理请求发送之前和之后运行逻辑。其中前半部分代码是处理请求的代码,处理完成后调用真实被代理的服务,被代理的服务响应结果,结果会被 filter 中后半部分代码进行操作,操作完成后把结果返回给 web handler,再返回给 handler mapping,最终响应给客户端。

3.常见的限流方法

3.1计数器法

设置一个计数器 counter,每当一个请求过来的时候,counter+1,如果 counter 的值大于阈值且当前请求与第一个请求的间隔时间还在限定的时间之内,那么说明请求数过多;如果该请求与第一个
请求的间隔时间大于限定时间,且 counter 的值还在限流范围内,那么就重置 counter。

缺点:精度太低,无法处理临界问题。以 QPS = 100 举例,假设从第一个请求开始计时,每一个请求让计数器加一,当到达 100 以后,其他的请求都拒绝,如果一秒内前 200ms 请求数量到达了100,那么后面 800ms 中的所有请求都被拒绝了,导致出现“突刺现象”。

3.2滑动窗口法

将窗口更加细分,每个窗口都有自己的计数器,当总计算达到限定时,限流。这个滑动窗口只是将计算法变得更平滑而已。

缺点:治标不治本(仍会有突刺)。

假设时间周期为1min,将1min再分为2个小周期,统计每个小周期的访问数量,则可以看到,第一个时间周期内,访问数量为75,第二个时间周期内,访问数量为100,超过100的访问则被限流掉了。

3.3漏桶法

将容器比作一个漏斗,当请求进来时,相当于水倒入漏斗,然后从下端小口慢慢匀速的流出。不管上面流量多大,下面流出的速度始终保持不变。(利用队列实现)

缺点:无法应对短时间的突发流量。因为流出的是固定频率,其他流量只是放在桶中。
 

3.4令牌桶算法

 

在令牌桶算法中,存在一个桶,用来存放固定数量的令牌。算法中存在一种机制,以一定的速率往桶中放令牌。每次请求调用需要先获取令牌,只有拿到令牌,才有机会继续执行,否则选择选择等待可用的
令牌、或者直接拒绝。

  • 令牌桶是按照固定速率往桶中添加令牌,请求是否被处理需要看桶中令牌是否足够,当令牌数减为零时则拒绝新的请求;漏桶则是按照常量固定速率流出请求,流入请求速率任意,当流入的请求数
    累积到漏桶容量时,则新流入的请求被拒绝。
  • 令牌桶限制的是平均流入速率,允许突发请求,只要有令牌就可以处理;漏桶限制的是常量流出速率,即流出速率是一个固定常量值,比如都是1的速率流出,而不能一次是1,下次又是2,从而平滑突发流入速率。

4.令牌桶算法源码分析

令牌桶算法底层实现依赖于 RedisRateLimiter 类。

4.1限流 java 核心代码

@Override
@SuppressWarnings("unchecked")
public Mono<Response> isAllowed(String routeId, String id) {
   // 判断RedisRateLimiter是否初始化了
   if (!this.initialized.get()) {
      throw new IllegalStateException("RedisRateLimiter is not initialized");
   }


   // 根据服务应用id获取限流配置
   Config routeConfig = loadConfiguration(routeId);

   // How many requests per second do you want a user to be allowed to do?
   int replenishR
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值