Netflix Zuul 限流实例

限流是一种流量控制策略,用于限制对系统资源(如服务器、网络带宽、数据库连接等)的访问速率。它就像是在系统的入口处设置了一个 “阀门”,控制进入系统的请求数量或速率,以确保系统能够在其处理能力范围内稳定运行。

限流目的

保护系统稳定性

当大量请求瞬间涌入系统时,系统的资源(如 CPU、内存、I/O 等)可能会被耗尽。例如,一个 Web 应用服务器如果同时接收过多的 HTTP 请求,可能会导致服务器响应变慢甚至崩溃。通过限流,可以避免这种情况的发生,确保系统的响应时间和可用性。

防止恶意攻击

在网络环境中,存在分布式拒绝服务攻击(DDoS)等恶意行为。攻击者会发送大量请求来淹没目标系统,使其无法正常服务合法用户。限流可以作为一种防御手段,限制异常高流量的请求,减轻 DDoS 攻击对系统的影响。

公平分配资源

在多个用户或服务共享有限资源的场景下,限流可以确保每个用户或服务都能获得合理的资源份额。例如,在一个多租户的云服务环境中,通过对每个租户的请求进行限流,可以防止某个租户过度占用资源,从而保证其他租户的服务质量。

常见限流算法

计数器法

这是一种简单直观的限流方法。它使用一个计数器来记录在特定时间窗口内的请求数量。例如,设定一个时间窗口为 1 分钟,计数器初始值为 0。每收到一个请求,计数器就加 1。当计数器的值超过设定的阈值(如 100 个请求)时,就开始拒绝新的请求,直到下一个时间窗口开始,计数器清零。

但是这种方法存在一个问题,称为 “临界问题”。假设我们的阈值是 100,时间窗口是 1 分钟,在 59 秒的时候已经接收了 99 个请求,然后在第 60 秒的时候又接收了 100 个请求,这样在这 1 分钟内就处理了 199 个请求,超过了我们设定的限制。

滑动窗口法

为了解决计数器法的临界问题,滑动窗口法应运而生。它将时间窗口划分为多个小的子窗口,每个子窗口都有自己的计数器。例如,将 1 分钟的时间窗口划分为 6 个 10 秒的子窗口。每次有请求到来时,更新当前子窗口和总的请求计数器。当总的请求计数器超过阈值时,就进行限流。

这样可以更平滑地控制请求流量,避免了计数器法在时间窗口边界处可能出现的突发流量问题。

漏桶算法

可以把系统想象成一个底部有小孔的水桶。请求就像水一样流入桶中,桶底部的小孔以固定的速率将水(请求)流出。当水(请求)流入的速度超过流出的速度时,桶就会装满,多余的水(请求)就会溢出(被拒绝)。

这种算法的优点是能够平滑请求流量,缺点是对于突发流量的处理不够灵活,因为请求只能按照固定的速率流出。

令牌桶算法

令牌桶算法中有一个令牌桶,系统会以固定的速率向桶中放入令牌。当有请求到来时,需要从桶中获取一个令牌才能被处理。如果桶中没有令牌了,那么请求就会被限流。

与漏桶算法不同的是,令牌桶算法允许一定程度的突发流量。例如,如果令牌桶中积累了一些令牌,当突发大量请求到来时,只要有足够的令牌,这些请求就可以立即被处理。

spring-cloud-zuul-ratelimit

spring-cloud-zuul-ratelimit 是一个用于在 Spring Cloud Zuul 网关中实现限流的库。

该库主要基于 Spring Boot 和 Zuul 构建,它允许你在 Zuul 网关层面对进入系统的请求流量进行速率限制,例如可以限制某个 API 端点在一定时间内允许通过的请求数量。

注意了,spring-cloud-zuul-ratelimit 组件库托管在 github 上面,如下图:

a887f35c08f197b58f6d73486939a7be_1734416551527-31dab686-4232-4ccf-81bf-777a0cae8482.png

组件库地址:https://github.com/marcosbarbero/spring-cloud-zuul-ratelimit

限流简单示例

引入依赖

下面将引入 spring-cloud-zuul-ratelimit 和 redis 的依赖信息:

<!-- 用于zuul限流 -->
<dependency>
  <groupId>com.marcosbarbero.cloud</groupId>
  <artifactId>spring-cloud-zuul-ratelimit</artifactId>
  <version>2.4.0.RELEASE</version>
</dependency>
<!-- 基于redis来计数 -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

为什么需要引入 redis 依赖?该示例将基于 Redis 来实现限流,Redis 需要保存服务访问信息,限流等信息。

项目配置

下面是项目中配置 redis 的配置,使用本地 redis:

spring:
  # ...
  redis:
    host: localhost
    port: 6379
    database: 0

下面是 zuul 限流的配置:

# Zuul 服务限流
zuul:
  # 服务限流
  ratelimit:
    # 开启限流
    enabled: true
    # 使用 redis 存储限流数据
    repository: redis
    # policy-list 自定义配置,局部生效
    policy-list:
      service-product:
        - limit: 2 # 限制一个时间窗口内 2 次
          refresh-interval: 60 # 60s 内请求超过2次,服务端抛出异常,60s 后可以恢复正常请求
          type:
            - url
            - origin
    # 默认限制,所有服务都有效
    default-policy-list:
      - limit: 10    # 限制次数,每刷新一次次数+1
        quota: 1000  # 窗口对应的请求时间限制
        refresh-interval: 60 # 多少秒后刷新计数
        type: # optional 限制类型
          - origin  # url 包括ip+接口
          - url
          - user
  # 路由配置
  routes:
    service-order:
      path: /api/order/**
      service-id: service-order
    service-product:
      path: /api/product/**
      service-id: service-product

重启&验证

完成上述配置后,重启项目,如下图:

67bf2ef728d7480e274741aade0f8825_1734419378844-4c62a1c7-fcb1-42d6-bb6a-dda1b52a76ac.png

此时,使用浏览器访问 http://localhost:9000/api/product/product/1 地址,如果在一分钟内访问超过两次,则会出现如下图错误信息:

39ac79ea8df08ab78c1fc65a2676d8ca_1734419412501-56d5ebba-65bd-41ce-aa0d-e5aadd6de35c.png

上图错误信息说明,触发了限流。

最后,使用 RedisDesktopManager(点击下载) 工具连接到 Redis,查看限流相关的信息,如下图:

d650c29223f00db97e3c4c60df581da7_1734419350206-5412eab4-e6a2-4cb8-9031-291d4e7635d4.png

点击下载/查看本教程相关资料或者源代码。
说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号