面试官:网关如何实现限流?

网关(Gateway)是微服务中不可缺少的一部分,它是微服务中提供了统一访问地址的组件,充当了客户端和内部微服务之间的中介。网关主要负责流量路由和转发,将外部请求引导到相应的微服务实例上,同时提供一些功能,如身份认证、授权、限流、监控、日志记录等。

网关的主要作用有以下几个:

  1. 路由功能:网关可以根据目标地址的不同,选择最佳的路径将数据包从源网络路由到目标网络。它通过维护路由表来确定数据包的转发方向,并选择最优的路径。
  2. 安全控制(统一认证授权):网关可以实施网络安全策略,对进出的数据包进行检查和过滤。它可以验证和授权来自源网络的数据包,并阻止未经授权的访问。防火墙是一种常见的网关设备,用于过滤和保护网络免受恶意攻击和未经授权的访问。
  3. 协议转换:不同网络使用不同的通信协议,网关可以进行协议转换,使得不同网络的设备可以互相通信。例如,例如将 HTTPS 协议转换成 HTTP 协议。
  4. 网络地址转换(NAT):网关还可以执行网络地址转换,将内部网络使用的私有 IP 地址转换为外部网络使用的公共 IP 地址,以实现多台计算机共享一个公共 IP 地址出去上网。

1.关于限流

为了保护后端微服务免受突发高流量请求的影响,确保系统的稳定和可靠性,所以在网关层必须"限流"操作。

限流是一种流量控制的策略,用于限制系统处理请求的速率或数量,以保护系统免受过载或攻击的影响。通过限制请求的数量或速率,可以平衡系统和资源之间的压力,确保系统在可接受的范围内运行。

限流的常见策略通常有以下几种:

  1. 请求速率限流:限制单位时间内系统可以接受的最大请求数量。例如,每秒最多处理 100 个请求。当请求超过限制时,可以选择拒绝或延迟处理这些请求。
  2. 并发请求数限流:限制同时处理的请求数量。例如,限制系统只能同时处理100个并发请求。当并发请求数超过限制时,可以选择拒绝或排队等待。
  3. 用户级别限流:根据用户进行限流,限制每个用户的请求频率或数量。例如,限制每个用户每分钟只能发送 10 个请求。当用户请求超过限制时,可以选择拒绝或延迟处理。
  4. API 级别限流:根据 API 接口进行限流,限制每个接口的请求频率或数量。例如,限制某个接口每秒只能处理 50 个请求。当接口请求超过限制时,可以选择拒绝或延迟处理。

当然,我们也可以在程序中使用多种策略混合限流,以保证内部微服务的稳定性。

2.如何实现限流?

了解了网关和限流的相关内容之后,我们以目前主流的网关组件 Spring Cloud Gateway 为例,来实现一下限流功能。

Spring Cloud Gateway 实现限流的方式有两种:

  1. 使用内置 Filter(过滤器)实现限流。
  2. 使用限流组件 Spring Cloud Alibaba Sentinel 或者 Spring Cloud Netflix Hystrix 实现限流。

那既然 Spring Cloud Gateway 中已经内置了限流功能,那我们接下来就来看 Spring Cloud Gateway 内置限流是如何实现的?

Spring Cloud Gateway 内置的限流器为 RequestRateLimiter GatewayFilter Factory,官网说明文档:docs.spring.io/spring-clou...

Spring Cloud Gateway 支持和 Redis 一起来实现限流功能,它的实现步骤如下:

  1. 在网关项目中添加 Redis 框架依赖
  2. 创建限流规则
  3. 配置限流过滤器

具体实现如下。

2.1 添加 Redis 框架依赖

在项目的 pom.xml 中,添加以下配置信息(添加 Redis 框架依赖支持):

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

2.2 创建限流规则

接下来我们新建一个限流规则定义类,实现一下根据 IP 进行限流的功能,实现示例代码如下:

java 复制代码
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
public class IpAddressKeyResolver implements KeyResolver {
    @Override
    public Mono<String> resolve(ServerWebExchange exchange) {
        return Mono.just(exchange.getRequest().getRemoteAddress().
                         getHostString());
    }
}

这一步其实是在配置限流器的限流参数 KeyResolver,也就是限流功能的依赖"凭证"。

PS:当然,我们还可以通过 URL、方法名、用户等进行限流操作,只需要修改此步骤中的限流凭证,也就是 KeyResolver 即可。

2.3 配置限流过滤器

在网关项目的配置文件中,添加以下配置信息:

yaml 复制代码
spring:
  cloud:
    gateway:
      routes:
        - id: retry
          uri: lb://nacos-discovery-demo
          predicates:
            - Path=/retry/**
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 1
                redis-rate-limiter.burstCapacity: 1
                keyResolver: '#{@ipAddressKeyResolver}' # spEL表达式
  data:
    redis:
      host: 127.0.0.1
      port: 16379
      database: 0

其中,name 必须等于"RequestRateLimiter"内置限流过滤器,其他参数的含义如下:

  • redis-rate-limiter.replenishRate:令牌填充速度:每秒允许请求数。
  • redis-rate-limiter.burstCapacity:令牌桶容量:最大令牌数。
  • keyResolver:根据哪个 key 进行限流,它的值是 spEL 表达式。

SpEL(Spring Expression Language,Spring 表达式语言)是 Spring 框架中用于提供灵活、强大的表达式解析和求值功能的统一表达式语言。它可以在运行时动态地解析和求值字符串表达式,通常用于配置文件中的属性值、注解、XML 配置等地方。

注意事项

当 Spring Cloud Gateway 配合 Redis 实现限流的时候,它对于 Redis 的版本是有要求的,因为它在限流时调用了一个 Redis 高版本的函数,所以 Redis Server 版本太低,限流无效,Redis Server 最好是 5.X 以上。

2.4 限流测试

最后,我们频繁的访问:http://localhost:10086/retry/test 就会看到如下限流信息:

3.限流实现算法

Spring Cloud Gateway 内置限流功能使用的算法是令牌桶限流算法

令牌桶限流算法 :令牌按固定的速率被放入令牌桶中,桶中最多存放 N 个令牌(Token),当桶装满时,新添加的令牌被丢弃或拒绝。当请求到达时,将从桶中删除 1 个令牌。令牌桶中的令牌不仅可以被移除,还可以往里添加,所以为了保证接口随时有数据通过,必须不停地往桶里加令牌。由此可见,往桶里加令牌的速度就决定了数据通过接口的速度。我们通过控制往令牌桶里加令牌的速度从而控制接口的流量。 令牌桶执行流程如下图所示: 常见的限流算法还有:计数器算法、滑动计数器算法、漏桶算法等,更多介绍参考我之前写个的文章:www.javacn.site/interview/s...

4.限流实现原理

Spring Cloud Gateway 执行过程如下图所示: 从图中可以看出,所有的请求来了之后,会先走过滤器,只有过滤器通过之后,才能调用后续的内部微服务,这样我们就可以通过过滤器来控制微服务的调用,从而实现限流功能了。

Spring Cloud Gateway 过滤器是基于令牌桶算法来限制请求的速率,该过滤器根据配置的限流规则,在指定的时间窗口内分配一定数量的令牌,每个令牌代表一个允许通过的请求,当一个请求到达时,如果没有可用的令牌,则请求将被阻塞或拒绝。

令牌桶的执行过程如下:

  1. 初始化:在加载过滤器工厂时,会基于给定的限流规则创建一个限流器,该限流器包含了令牌桶算法的逻辑。默认情况下,令牌桶是按照固定速率进行填充,也可以配置为令牌桶按照令牌令牌的方式进行填充。
  2. 请求处理:每当有请求进来时,限流器会检查当前令牌桶中是否有可用的令牌。如果有可用的令牌,则请求会被放行,令牌桶中的令牌数量减少;如果没有可用的令牌,则请求会被阻塞或拒绝。
  3. 令牌桶填充:限流器会定期填充令牌桶,即向令牌桶中添加新的令牌。填充的速率取决于限流规则中配置的速率值。
  4. 令牌桶容量控制:限流器还会根据限流规则中配置的令牌桶容量,控制令牌桶中的令牌数量。如果令牌桶已满,则多余的令牌会被丢弃。

小结

主流网关组件 Spring Cloud Gateway 实现限流的方式主要有两种:内置限流过滤器和外部限流组件,如 Sentinel、Hystrix 等。而最简单的限流功能,我们只需要使用 Spring Cloud Gateway 过滤器 + Redis 即可(实现),其使用的是令牌桶的限流算法来实现限流功能的。

本文已收录到我的面试小站 www.javacn.site,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息队列等模块。

相关推荐
JaguarJack4 分钟前
PHP 现代特性速查 写出更简洁安全的代码(中篇)
后端·php
echoyu.5 分钟前
java源代码、字节码、jvm、jit、aot的关系
java·开发语言·jvm·八股
彭于晏Yan1 小时前
IDEA如何进行远程Debug
java·ide
Victor3561 小时前
Redis(104)Redis的最大数据量是多少?
后端
Victor3561 小时前
Redis(105)Redis的数据类型支持哪些操作?
后端
木木子99994 小时前
业务架构、应用架构、数据架构、技术架构
java·开发语言·架构
qq_5470261796 小时前
Flowable 工作流引擎
java·服务器·前端
鼓掌MVP7 小时前
Java框架的发展历程体现了软件工程思想的持续进化
java·spring·架构
编程爱好者熊浪8 小时前
两次连接池泄露的BUG
java·数据库
lllsure8 小时前
【Spring Cloud】Spring Cloud Config
java·spring·spring cloud