跳到主要内容

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_addrconsumer_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-authlimit-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_addrconsumer_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