Traefik RateLimit 中间件文档
RateLimit(限流)
rateLimit 中间件确保服务能接收到公平数量的请求,并允许你定义"公平"的含义。
它基于令牌桶(token bucket)算法实现。 在这个类比中,average 和 period 参数定义了桶的填充速率,burst 是桶的容量(体积)。
速率与突发(Rate and Burst)
速率通过 average 除以 period 来定义。 对于低于 1 req/s 的速率,请将 period 定义为大于一秒。
配置示例
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: falseKubernetes 格式
# 这里允许每秒 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。 | 否 | |
redis | Redis 配置通过使用 Redis 在多个 Traefik 实例间存储限流令牌来启用分布式限流。这允许你在 Traefik 代理集群中强制实施一致的速率限制。当未配置 Redis 时,Traefik 使用内存存储进行限流,这仅对单个 Traefik 实例有效。 | 否 | |
redis.endpoints | 用于分布式限流的 Redis 服务器端点列表。你可以为 Redis 集群或高可用设置指定多个端点。 | "127.0.0.1:6379" | 否 |
redis.username | Redis 认证的用户名。 | "" | 否 |
redis.password | Redis 认证的密码。在 Kubernetes 中,这些可以通过 secrets 提供。 | "" | 否 |
redis.db | 要选择的 Redis 数据库编号。 | 0 | 否 |
redis.poolSize | 池中连接的基础数量。如果设置为 0,则默认为 runtime.GOMAXPROCS 报告的每个 CPU 核心 10 个连接。如果池中没有足够的连接,将分配超过 poolSize 的新连接,最多到 maxActiveConns。 | 0 | 否 |
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:depth、excludedIPs 和 ipv6Subnet。
作为中间件,限流在实际代理到后端之前发生。 此外,前一跳网络节点仅在代理的最后阶段被附加到 X-Forwarded-For,即在限流已经通过之后。 因此,在限流期间,由于前一跳尚未出现在 X-Forwarded-For 中,因此无法找到和/或依赖它。
sourceCriterion.ipStrategy.ipv6Subnet
此策略仅适用于 Depth 和 RemoteAddr 策略。 如果提供了 ipv6Subnet 且选中的 IP 是 IPv6,则该 IP 会被转换为其所属子网的第一个 IP。
这对于将 IPv6 地址分组到子网中很有用,可防止通过获取新 IPv6 来绕过此中间件。
- 如果
ipv6Subnet的值在 0-128 范围之外,则会被忽略。
ipv6Subnet 示例
| IP | ipv6Subnet | clientIP |
|---|---|---|
"::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-For | depth | clientIP |
|---|---|---|
"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 旨在解决两类稍微不同的用例:
区分位于同一组反向代理后的 IP,使它们中的每一个都独立地对各自的限流"桶"做出贡献(参见令牌桶)。在这种情况下,应将
excludedIPs设置为匹配要排除的X-Forwarded-For IP列表,以便找到实际的 clientIP。示例:将每个 IP 用作不同的来源:
X-Forwarded-For excludedIPs clientIP "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"将一组 IP 分组在一起(同样位于一组公共反向代理之后),使它们被视为同一来源,并都贡献到同一限流桶。
示例:将 IP 分组在一起作为同一来源:
X-Forwarded-For excludedIPs clientIP "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 的商业支持。