limit-conn
limit-conn 插件通过限制并发连接数来限制请求速率。根据配置,超过阈值的请求将被延迟或拒绝,从而确保受控的资源使用并防止过载。
示例
以下示例演示了如何在不同场景下配置 limit-conn。
基于远程地址进行速率限制
以下示例演示了如何使用 limit-conn 通过 remote_addr 对请求进行速率限制,并配置连接数和突发阈值。
创建一个启用了 limit-conn 插件的路由:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "limit-conn-route",
"uri": "/get",
"plugins": {
"limit-conn": {
"conn": 2,
"burst": 1,
"default_conn_delay": 0.1,
"key_type": "var",
"key": "remote_addr",
"policy": "local",
"rejected_code": 429
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
❶ conn:允许 2 个并发请求。
❷ burst:允许 1 个额外的并发请求。
❸ default_conn_delay:允许超过 conn + burst 的并发请求有 0.1 秒的处理延迟。
❹ key_type:设置为 vars,以将 key 解释为变量。
❺ key:通过请求的 remote_address 计算速率限制计数。
❻ policy:使用内存中的本地计数器。
❼ rejected_code:将拒绝状态码设置为 429。
向该路由发送五个并发请求:
seq 1 5 | xargs -n1 -P5 bash -c 'curl -s -o /dev/null -w "Response: %{http_code}\n" "http://127.0.0.1:9080/get"'
你应该会看到类似于以下的响应,其中多余的请求被拒绝:
Response: 200
Response: 200
Response: 200
Response: 429
Response: 429
基于远程地址和消费者名称进行速率限制
以下示例演示了如何使用 limit-conn 通过变量组合 remote_addr 和 consumer_name 对请求进行速率限制。
创建一个消费者 john:
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "john"
}'
为该消费者创建 key-auth 凭证:
curl "http://127.0.0.1:9180/apisix/admin/consumers/john/credentials" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "cred-john-key-auth",
"plugins": {
"key-auth": {
"key": "john-key"
}
}
}'
创建第二个消费者 jane:
curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "jane"
}'
为该消费者创建 key-auth 凭证:
curl "http://127.0.0.1:9180/apisix/admin/consumers/jane/credentials" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "cred-jane-key-auth",
"plugins": {
"key-auth": {
"key": "jane-key"
}
}
}'
创建一个启用了 key-auth 和 limit-conn 插件的路由:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "limit-conn-route",
"uri": "/get",
"plugins": {
"key-auth": {},
"limit-conn": {
"conn": 2,
"burst": 1,
"default_conn_delay": 0.1,
"rejected_code": 429,
"key_type": "var_combination",
"key": "$remote_addr $consumer_name"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
❶ key-auth:在路由上启用密钥认证。
❷ key_type:设置为 var_combination,以将 key 解释为变量组合。
❸ key:设置为 $remote_addr $consumer_name,以根据远程地址和消费者应用速率限制配额。
作为消费者 john 发送五个并发请求:
seq 1 5 | xargs -n1 -P5 bash -c 'curl -s -o /dev/null -w "Response: %{http_code}\n" "http://127.0.0.1:9080/get" -H "apikey: john-key"'
你应该会看到类似于以下的响应,其中多余的请求被拒绝:
Response: 200
Response: 200
Response: 200
Response: 429
Response: 429
立即作为消费者 jane 发送五个并发 请求:
seq 1 5 | xargs -n1 -P5 bash -c 'curl -s -o /dev/null -w "Response: %{http_code}\n" "http://127.0.0.1:9080/get" -H "apikey: jane-key"'
你应该也会看到类似于以下的响应,其中多余的请求被拒绝:
Response: 200
Response: 200
Response: 200
Response: 429
Response: 429
在这种情况下,插件通过变量组合 remote_addr 和 consumer_name 进行速率限制,这意味着每个消费者的配额是独立的。
限制 WebSocket 连接速率
以下示例演示了如何使用 limit-conn 插件来限制并发 WebSocket 连接数。
启动一个示例上游 WebSocket 服务器:
docker run -d \
-p 8080:8080 \
--name websocket-server \
--network=apisix-quickstart-net \
jmalloc/echo-server
创建一条到 WebSocket 服务器端点的路由,并为该路由启用 WebSocket:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT -d '
{
"id": "ws-route",
"uri": "/.ws",
"plugins": {
"limit-conn": {
"conn": 2,
"burst": 1,
"default_conn_delay": 0.1,
"key_type": "var",
"key": "remote_addr",
"rejected_code": 429
}
},
"enable_websocket": true,
"upstream": {
"type": "roundrobin",
"nodes": {
"websocket-server:8080": 1
}
}
}'
❶ 为路由启用 WebSocket。
❷ 替换为你的 WebSocket 服务器地址。
安装一个 WebSocket 客户端,例如 websocat(如果你还没有安装)。通过路由与 WebSocket 服务器建立连接:
websocat "ws://127.0.0.1:9080/.ws"
在终端中发送一条 "hello" 消息,你应该会看到 WebSocket 服务器回显相同的消息:
Request served by 1cd244052136
hello
hello
再打开三个终端会话并运行:
websocat "ws://127.0.0.1:9080/.ws"
当你尝试与服务器建立 WebSocket 连接时,你应该会看到最后一个终端会话打印 429 Too Many Requests,这是由于速率限制的影响。
使用 Redis 服务器在 APISIX 节点之间共享配额
以下示例演示了使用 Redis 服务器在多个 APISIX 节点之间对请求进行速率限制,从而使不同的 APISIX 节点共享相同的速率限制配额。
在每个 APISIX 实例上,创建具有以下配置的路由。相应地调整 Admin API 的地址。
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "limit-conn-route",
"uri": "/get",
"plugins": {
"limit-conn": {
"conn": 1,
"burst": 1,
"default_conn_delay": 0.1,
"rejected_code": 429,
"key_type": "var",
"key": "remote_addr",
"policy": "redis",
"redis_host": "192.168.xxx.xxx",
"redis_port": 6379,
"redis_password": "p@ssw0rd",
"redis_database": 1
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
❶ policy:设置为 redis 以使用 Redis 实例进行速率限制。
❷ redis_host:设置为 Redis 实例的 IP 地址。
❸ redis_port:设置为 Redis 实例的监听端口。
❹ redis_password:如果有,设置为 Redis 实例的密码。
❺ redis_database:设置为 Redis 实例中的数据库编号。
向该路由发送五个并发请求:
seq 1 5 | xargs -n1 -P5 bash -c 'curl -s -o /dev/null -w "Response: %{http_code}\n" "http://127.0.0.1:9080/get"'
你应该会看到类似于以下的响应,其中多余的请求被拒绝:
Response: 200
Response: 200
Response: 429
Response: 429
Response: 429
这表明配置在不同 APISIX 实例中的两个路由共享相同的配额。
使用 Redis 集群在 APISIX 节点之间共享配额
你也可以使用 Redis 集群在多个 APISIX 节点之间应用相同的配额,从而使不同的 APISIX 节点共享相同的速率限制配额。
确保你的 Redis 实例运行在集群模式(Cluster Mode)。limit-conn 插件配置至少需要两个节点。
在每个 APISIX 实例上,创建具有以下配置的路由。相应地调整 Admin API 的地址。
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "limit-conn-route",
"uri": "/get",
"plugins": {
"limit-conn": {
"conn": 1,
"burst": 1,
"default_conn_delay": 0.1,
"rejected_code": 429,
"key_type": "var",
"key": "remote_addr",
"policy": "redis-cluster",
"redis_cluster_nodes": [
"192.168.xxx.xxx:6379",
"192.168.xxx.xxx:16379"
],
"redis_password": "p@ssw0rd",
"redis_cluster_name": "redis-cluster-1",
"redis_cluster_ssl": true
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
❶ policy:设置为 redis-cluster 以使用 Redis 集群进行速率限制。
❷ redis_cluster_nodes:设置为 Redis 集群中的 Redis 节点地址。
❸ redis_password:如果有,设置为 Redis 集群的密码。
❹ redis_cluster_name:设置为 Redis 集群名称。
❺ redis_cluster_ssl:启用与 Redis 集群的 SSL/TLS 通信。
向该路由发送五个并发请求:
seq 1 5 | xargs -n1 -P5 bash -c 'curl -s -o /dev/null -w "Response: %{http_code}\n" "http://127.0.0.1:9080/get"'
你应该会看到类似于以下的响应,其中多余的请求被拒绝:
Response: 200
Response: 200
Response: 429
Response: 429
Response: 429
这表明配置在不同 APISIX 实例中的两个路由共享相同的配额。
基于规则的速率限制
以下示例演示了如何配置 limit-conn 以根据请求属性应用不同的速率限制规则(从 API7 Enterprise 3.8.17 开始可用)。在此示例中,速率限制基于代表调用者访问层级的 HTTP 头值应用。
请注意,所有规则按顺序应用。如果配置的键不存在,则将跳过相应的规则。
除了 HTTP 头之外,你还可以根据其他内置变量来制定规则,以实现更灵活和细粒度的速率限制策略。
创建一个启用了 limit-conn 插件的路由,该插件根据请求头应用不同的速率限制,允许每个订阅(X-Subscription-ID)进行速率限制,并对试用用户(X-Trial-ID)强制执行更严格的限制:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "limit-conn-rules-route",
"uri": "/get",
"plugins": {
"limit-conn": {
"rejected_code": 429,
"default_conn_delay": 0.1,
"rules": [
{
"key": "${http_x_subscription_id}",
"conn": "${http_x_custom_conn ?? 5}",
"burst": 1
},
{
"key": "${http_x_trial_id}",
"conn": 1,
"burst": 1
}
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
❶ 使用 X-Subscription-ID 请求头的值作为速率限制键。
❷ 根据 X-Custom-Conn 头动态设置请求连接。如果未提供该头,则应用默认并发连接数 5。
❸ 使用 X-Trial-ID 请求头的值作为速率限制键。
要验证速率限制,使用相同的订阅 ID 发送 7 个并发请求到该路由:
seq 1 7 | xargs -n1 -P7 bash -c 'curl -s -o /dev/null -w "Response: %{http_code}\n" "http://127.0.0.1:9080/get" -H "X-Subscription-ID: sub-123456789"'
你应该会看到以下响应,显示当未提供 X-Custom-Conn 头时,应用了 5 个并发连接限制和 1 个突发请求:
Response: 429
Response: 200
Response: 200
Response: 200
Response: 200
Response: 200
Response: 200
使用相同的订阅 ID 发送 5 个并发请求到该路由,并将 X-Custom-Conn 头设置为 1:
seq 1 5 | xargs -n1 -P5 bash -c 'curl -s -o /dev/null -w "Response: %{http_code}\n" "http://127.0.0.1:9080/get" -H "X-Subscription-ID: sub-123456789" -H "X-Custom-Conn: 1"'
你应该会看到以下响应,显示应用了 1 个并发连接限制和 1 个突发请求:
Response: 429
Response: 429
Response: 429
Response: 200
Response: 200
最后,使用试用 ID 头生成 5 个请求到该路由:
seq 1 5 | xargs -n1 -P5 bash -c 'curl -s -o /dev/null -w "Response: %{http_code}\n" "http://127.0.0.1:9080/get" -H "X-Trial-ID: trial-123456789"'
你应该会看到以下响应,显示应用了 1 个并发连接限制和 1 个突发请求:
Response: 429
Response: 429
Response: 429
Response: 200
Response: 200