Skip to content

Traefik RateLimit 中间件文档

RateLimit(限流)

rateLimit 中间件确保服务能接收到公平数量的请求,并允许你定义"公平"的含义。

它基于令牌桶(token bucket)算法实现。 在这个类比中,averageperiod 参数定义了桶的填充速率burst 是桶的容量(体积)。

速率与突发(Rate and Burst)

速率通过 average 除以 period 来定义。 对于低于 1 req/s 的速率,请将 period 定义为大于一秒。

配置示例

YAML 格式

yaml
# 这里允许每秒 100 个请求的平均速率。
# 此外,还允许 200 个请求的突发量。
# Redis 分布式限流配置了所有可用选项。
http:
  middlewares:
    test-ratelimit:
      rateLimit:
        average: 100
        period: 1s
        burst: 200
        redis:
          endpoints:
            - "redis-primary.example.com:6379"
            - "redis-replica.example.com:6379"
          username: "ratelimit-user"
          password: "secure-password"
          db: 2
          poolSize: 50
          minIdleConns: 10
          maxActiveConns: 200
          readTimeout: 3s
          writeTimeout: 3s
          dialTimeout: 5s
          tls:
            ca: "/etc/ssl/redis-ca.crt"
            cert: "/etc/ssl/redis-client.crt"
            key: "/etc/ssl/redis-client.key"
            insecureSkipVerify: false

Kubernetes 格式

yaml
# 这里允许每秒 100 个请求的平均速率。
# 此外,还允许 200 个请求的突发量。
# Redis 分布式限流配置了所有可用选项。
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: test-ratelimit
spec:
  rateLimit:
    average: 100
    period: 1s
    burst: 200
    redis:
      endpoints:
        - "redis-primary.example.com:6379"
        - "redis-replica.example.com:6379"
      secret: redis-credentials
      db: 2
      poolSize: 50
      minIdleConns: 10
      maxActiveConns: 200
      readTimeout: 3s
      writeTimeout: 3s
      dialTimeout: 5s
      tls:
        caSecret: redis-ca
        certSecret: redis-client-cert
        insecureSkipVerify: false

---
apiVersion: v1
kind: Secret
metadata:
  name: redis-credentials
  namespace: default
data:
  username: cmF0ZWxpbWl0LXVzZXI=  # base64 编码后的 "ratelimit-user"
  password: c2VjdXJlLXBhc3N3b3Jk  # base64 编码后的 "secure-password"

注意:完整的 Labels 和 Tags 配置示例与其他中间件类似,此处省略以保持简洁。

配置选项

字段描述默认值必填
average用于在 period 时间内定义速率的请求数。0 表示不限流。更多信息参见速率与突发0
period用于定义速率的时间段。更多信息参见速率与突发1s
burst在同一时刻允许通过的最大请求数。更多信息参见速率与突发1
sourceCriterion.requestHost是否将请求主机视为来源。更多信息参见 sourceCriterion。false
sourceCriterion.requestHeaderName用于对传入请求进行分组的请求头名称。更多信息参见 sourceCriterion。""
sourceCriterion.ipStrategy.depth从右起在 X-Forwarded-For 头中选择 IP 的深度位置。0 表示无深度。如果大于 X-Forwarded-For 中的 IP 总数,则 client IP 为空。如果大于 0,则忽略 excludedIPs 选项。更多信息参见 sourceCriterion。0
sourceCriterion.ipStrategy.excludedIPs允许扫描 X-Forwarded-For 头并选择第一个不在该列表中的 IP。如果指定了 depth,则忽略 excludedIPs
sourceCriterion.ipStrategy.ipv6Subnet如果提供了 ipv6Subnet 且选中的 IP 是 IPv6,则该 IP 会被转换为其所属子网的第一个 IP。更多信息参见 sourceCriterion。
redisRedis 配置通过使用 Redis 在多个 Traefik 实例间存储限流令牌来启用分布式限流。这允许你在 Traefik 代理集群中强制实施一致的速率限制。当未配置 Redis 时,Traefik 使用内存存储进行限流,这仅对单个 Traefik 实例有效。
redis.endpoints用于分布式限流的 Redis 服务器端点列表。你可以为 Redis 集群或高可用设置指定多个端点。"127.0.0.1:6379"
redis.usernameRedis 认证的用户名。""
redis.passwordRedis 认证的密码。在 Kubernetes 中,这些可以通过 secrets 提供。""
redis.db要选择的 Redis 数据库编号。0
redis.poolSize池中连接的基础数量。如果设置为 0,则默认为 runtime.GOMAXPROCS 报告的每个 CPU 核心 10 个连接。如果池中没有足够的连接,将分配超过 poolSize 的新连接,最多到 maxActiveConns0
redis.minIdleConns池中保持的最小空闲连接数。当建立新连接较慢时很有用。值为 0 表示不会自动关闭空闲连接。0
redis.maxActiveConns池在任何给定时刻可以分配的最大连接数。值为 0 表示无限制。0
redis.readTimeout套接字读取超时。如果达到,命令将以超时失败而不会阻塞。零表示无超时。3s
redis.writeTimeout套接字写入超时。如果达到,命令将以超时失败而不会阻塞。零表示无超时。3s
redis.dialTimeout建立新连接的超时。零表示无超时。5s
redis.tls.ca用于 Redis 安全连接的证书颁发机构(CA)路径,默认为系统捆绑包。""
redis.tls.cert用于 Redis 安全连接的公钥证书路径。设置此选项时,key 选项是必需的。""
redis.tls.key用于 Redis 安全连接的私钥路径。设置此选项时,cert 选项是必需的。""
redis.tls.insecureSkipVerify如果 insecureSkipVerify 为 true,则到 Redis 的 TLS 连接将接受服务器提供的任何证书,无论其覆盖的主机名是什么。false

sourceCriterion

sourceCriterion 选项定义将哪些请求分组为来自同一来源的标准。 如果同时定义多个策略,则会引发错误。 如果未设置任何策略,则默认使用请求的远程地址字段(作为 ipStrategy)。

ipStrategy

ipStrategy 选项定义了三个参数,配置 Traefik 如何确定客户端 IP:depthexcludedIPsipv6Subnet

作为中间件,限流在实际代理到后端之前发生。 此外,前一跳网络节点仅在代理的最后阶段被附加到 X-Forwarded-For,即在限流已经通过之后。 因此,在限流期间,由于前一跳尚未出现在 X-Forwarded-For 中,因此无法找到和/或依赖它。

sourceCriterion.ipStrategy.ipv6Subnet

此策略仅适用于 DepthRemoteAddr 策略。 如果提供了 ipv6Subnet 且选中的 IP 是 IPv6,则该 IP 会被转换为其所属子网的第一个 IP。

这对于将 IPv6 地址分组到子网中很有用,可防止通过获取新 IPv6 来绕过此中间件。

  • 如果 ipv6Subnet 的值在 0-128 范围之外,则会被忽略。
ipv6Subnet 示例
IPipv6SubnetclientIP
"::abcd:1111:2222:3333"64"::0:0:0:0"
"::abcd:1111:2222:3333"80"::abcd:0:0:0:0"
"::abcd:1111:2222:3333"96"::abcd:1111:0:0:0"

sourceCriterion.ipStrategy.depth

如果 depth 设置为 2,并且请求的 X-Forwarded-For 头是 "10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1",则"真实"客户端 IP 是 "10.0.0.1"(在深度 4 处),但用作标准的 IP 是 "12.0.0.1"depth=2)。

X-Forwarded-FordepthclientIP
"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"1"13.0.0.1"
"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"3"11.0.0.1"
"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"5""

sourceCriterion.ipStrategy.excludedIPs

与名称可能暗示的不同,此选项不是关于从限流中排除某个 IP,因此不能用于为某些 IP 停用限流。

excludedIPs 旨在解决两类稍微不同的用例:

  1. 区分位于同一组反向代理后的 IP,使它们中的每一个都独立地对各自的限流"桶"做出贡献(参见令牌桶)。在这种情况下,应将 excludedIPs 设置为匹配要排除的 X-Forwarded-For IP 列表,以便找到实际的 clientIP。

    示例:将每个 IP 用作不同的来源:

    X-Forwarded-ForexcludedIPsclientIP
    "10.0.0.1,11.0.0.1,12.0.0.1""11.0.0.1,12.0.0.1""10.0.0.1"
    "10.0.0.2,11.0.0.1,12.0.0.1""11.0.0.1,12.0.0.1""10.0.0.2"
  2. 将一组 IP 分组在一起(同样位于一组公共反向代理之后),使它们被视为同一来源,并都贡献到同一限流桶。

    示例:将 IP 分组在一起作为同一来源:

    X-Forwarded-ForexcludedIPsclientIP
    "10.0.0.1,11.0.0.1,12.0.0.1""12.0.0.1""11.0.0.1"
    "10.0.0.2,11.0.0.1,12.0.0.1""12.0.0.1""11.0.0.1"
    "10.0.0.3,11.0.0.1,12.0.0.1""12.0.0.1""11.0.0.1"

在生产环境使用 Traefik OSS?

如果你在工作中使用 Traefik,可以考虑为其添加企业级 API 网关能力或获取 Traefik OSS 的商业支持。

基于 MIT 协议发布