limit-count-advanced
limit-count-advanced 插件使用固定窗口或滑动窗口算法,通过限制给定时间间隔内的请求数量来限制请求速率。超过配置配额的请求将被拒绝。
具体来说:
- 固定窗口算法在不重叠的时间间隔内跟踪请求。如果请求计数在任何间隔内超过配额,多余的请求将立即被拒绝,直到下一个时间窗口开始。
- 滑动窗口算法在重叠的间隔内跟踪请求,通过计算过去配置的时间段内的最近请求来平滑速率限制,而不管间隔何时开始。此方法减少了流量峰值,并且更有效地在一段时间内均匀分布请求。
此外,你可能还会看到以下速率限制响应头,其名称可以使用插件元数据进行自定义:
X-RateLimit-Limit:总配额X-RateLimit-Remaining:剩余配额X-RateLimit-Reset:计数器重置前的剩余秒数
偶尔,你可能会观察到 X-RateLimit-Remaining 出现较小的负值。这是可以接受的,因为滑动窗口算法是一种近似值。
本地限速与基于 Redis 的限速
limit-count-advanced 插件支持两种限速模式:
- 本地限速:每个网关实例独立实施限速。每个实例维护自己的计数器,因此当流量分散到多个实例时,实际限额约为“限额 × 实例数”。未设置
policy或将其设置为local时,这是默认模式。 - 基于 Redis 的限速:通过 Redis 在所有网关实例之间共享限额。所有实例共享同一配额,因此配置的限额适用于全部网关实例。
示例
除了 limit-count 插件功能外,该插件还支持滑动窗口算法。请参考 limit-count 插件以获取固定窗口示例,这些示例也可以在 limit-count-advanced 中配置。
以下示例演示了如何使用 limit-count-advanced 进行滑动窗口算法的速率限制。
使用本地计数器进行速率限制
以下示例演示了如何配置 limit-count-advanced 在路由上使用滑动窗口算法进行速率限制,并使用网关中的计数器。请注意,每个网关实例都有自己的计数器和独立配额。如果你有多个网关实例需要共享相同的配额,请参阅使用 Redis 服务器在网关之间共享配额。
创建一个启用了 limit-count-advanced 插件的路由,配置为每个远程地址在 10 秒滑动窗口内允许的配额为 5:
- Admin API
- ADC
- Ingress Controller
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "limit-count-sliding-route",
"uri": "/get",
"plugins": {
"limit-count-advanced": {
"policy": "local",
"count": 5,
"time_window": 10,
"rejected_code": 429,
"key_type": "var",
"key": "remote_addr",
"window_type": "sliding"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
services:
- name: httpbin
routes:
- uris:
- /get
name: limit-count-sliding-route
plugins:
limit-count-advanced:
policy: local
count: 5
time_window: 10
rejected_code: 429
key_type: var
key: remote_addr
window_type: sliding
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1
将配置同步到网关:
adc sync -f adc.yaml
- Gateway API
- APISIX CRD
apiVersion: v1
kind: Service
metadata:
namespace: aic
name: httpbin-external-domain
spec:
type: ExternalName
externalName: httpbin.org
---
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: aic
name: limit-count-advanced-plugin-config
spec:
plugins:
- name: limit-count-advanced
config:
policy: local
count: 5
time_window: 10
rejected_code: 429
key_type: var
key: remote_addr
window_type: sliding
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: aic
name: limit-count-sliding-route
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /get
filters:
- type: ExtensionRef
extensionRef:
group: apisix.apache.org
kind: PluginConfig
name: limit-count-advanced-plugin-config
backendRefs:
- name: httpbin-external-domain
port: 80
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
namespace: aic
name: httpbin-external-domain
spec:
ingressClassName: apisix
externalNodes:
- type: Domain
name: httpbin.org
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: aic
name: limit-count-sliding-route
spec:
ingressClassName: apisix
http:
- name: limit-count-sliding-route
match:
paths:
- /get
methods:
- GET
upstreams:
- name: httpbin-external-domain
plugins:
- name: limit-count-advanced
config:
policy: local
count: 5
time_window: 10
rejected_code: 429
key_type: var
key: remote_addr
window_type: sliding
应用配置:
kubectl apply -f limit-count-advanced-ic.yaml
每隔一秒生成 7 个请求到该路由:
for i in $(seq 7); do
(curl -I "http://127.0.0.1:9080/get" &)
sleep 1
done
你应该收到大多数请求的 HTTP/1.1 200 OK 响应,其余为 HTTP 429 Too Many Requests 响应。具体被拒绝的数量取决于第一个请求发送的时间。
使用 Redis 服务器在网关之间共享配额
以下示例演示了如何使用 Redis 服务器在多个网关节点之间使用滑动窗口算法进行速率限制,从而使不同的网关节点共享相同的速率限制配额。
在网关组中创建一个具有以下配置的路由:
- Admin API
- ADC
- Ingress Controller
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "limit-count-sliding-route",
"uri": "/get",
"plugins": {
"limit-count-advanced": {
"count": 1,
"time_window": 30,
"rejected_code": 429,
"key": "remote_addr",
"policy": "redis",
"redis_host": "192.168.xxx.xxx",
"redis_port": 6379,
"redis_password": "p@ssw0rd",
"redis_database": 1,
"window_type": "sliding",
"sync_interval": 0.2
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
services:
- name: httpbin
routes:
- uris:
- /get
name: limit-count-sliding-route
plugins:
limit-count-advanced:
count: 1
time_window: 30
rejected_code: 429
key: remote_addr
policy: redis
redis_host: "192.168.xxx.xxx"
redis_port: 6379
redis_password: "p@ssw0rd"
redis_database: 1
window_type: sliding
sync_interval: 0.2
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1
将配置同步到网关:
adc sync -f adc.yaml
- Gateway API
- APISIX CRD
apiVersion: v1
kind: Service
metadata:
namespace: aic
name: httpbin-external-domain
spec:
type: ExternalName
externalName: httpbin.org
---
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: aic
name: limit-count-advanced-plugin-config
spec:
plugins:
- name: limit-count-advanced
config:
count: 1
time_window: 30
rejected_code: 429
key: remote_addr
policy: redis
redis_host: "redis-service.aic.svc"
redis_port: 6379
redis_password: "p@ssw0rd"
redis_database: 1
window_type: sliding
sync_interval: 0.2
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: aic
name: limit-count-sliding-route
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /get
filters:
- type: ExtensionRef
extensionRef:
group: apisix.apache.org
kind: PluginConfig
name: limit-count-advanced-plugin-config
backendRefs:
- name: httpbin-external-domain
port: 80
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
namespace: aic
name: httpbin-external-domain
spec:
ingressClassName: apisix
externalNodes:
- type: Domain
name: httpbin.org
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: aic
name: limit-count-sliding-route
spec:
ingressClassName: apisix
http:
- name: limit-count-sliding-route
match:
paths:
- /get
methods:
- GET
upstreams:
- name: httpbin-external-domain
plugins:
- name: limit-count-advanced
config:
count: 1
time_window: 30
rejected_code: 429
key: remote_addr
policy: redis
redis_host: "redis-service.aic.svc"
redis_port: 6379
redis_password: "p@ssw0rd"
redis_database: 1
window_type: sliding
sync_interval: 0.2
应用配置:
kubectl apply -f limit-count-advanced-ic.yaml
❶ policy:设置为 redis 以使用 Redis 实例进行速率限制。
❷ redis_host:设置为 Redis 实例的 IP 地址。
❸ redis_port:设置为 Redis 实例的监听端口。
❹ redis_password:如果有,设置为 Redis 实例的密码。
❺ redis_database:设置为 Redis 实例中的数据库编号。
❻ window_type:将窗口类型设置为滑动窗口。
❼ sync_interval:设置同步间隔(可选)。
每隔一秒生成 7 个请求到该路由:
for i in $(seq 7); do
(curl -I "http://127.0.0.1:9080/get" &)
sleep 1
done
你应该收到大多数请求的 HTTP/1.1 200 OK 响应,其余为 HTTP 429 Too Many Requests 响应。具体被拒绝的数量取决于第一个请求发送的时间。这验证了配置在不同网关节点上的路由共享相同的配额。