Skip to main content

limit-count

The limit-count plugin uses a fixed window algorithm to limit the rate of requests by the number of requests within a given time interval. Requests exceeding the configured quota will be rejected.

You may see the following rate limiting headers in the response:

  • X-RateLimit-Limit: the total quota
  • X-RateLimit-Remaining: the remaining quota
  • X-RateLimit-Reset: number of seconds left for the counter to reset

Examples

The examples below demonstrate how you can configure limit-count in different scenarios.

Apply Rate Limiting by Remote Address

The following example demonstrates the rate limiting of requests by a single variable, remote_addr.

Create a route with limit-count plugin that allows for a quota of 1 within a 30-second window per remote address:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "limit-count-route",
"uri": "/get",
"plugins": {
"limit-count": {
"count": 1,
"time_window": 30,
"rejected_code": 429,
"key_type": "var",
"key": "remote_addr"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

Send a request to verify:

curl -i "http://127.0.0.1:9080/get"

You should see an HTTP/1.1 200 OK response.

The request has consumed all the quota allowed for the time window. If you send the request again within the same 30-second time interval, you should receive an HTTP/1.1 429 Too Many Requests response, indicating the request surpasses the quota threshold.

Apply Rate Limiting by Remote Address and Consumer Name

The following example demonstrates the rate limiting of requests by a combination of variables, remote_addr and consumer_name. It allows for a quota of 1 within a 30-second window per remote address and for each consumer.

Create a consumer john:

curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "john"
}'

Create key-auth credential for the consumer:

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"
}
}
}'

Create a second consumer jane:

curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "jane"
}'

Create key-auth credential for the consumer:

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"
}
}
}'

Create a route with key-auth and limit-count plugins:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "limit-count-route",
"uri": "/get",
"plugins": {
"key-auth": {},
"limit-count": {
"count": 1,
"time_window": 30,
"rejected_code": 429,
"key_type": "var_combination",
"key": "$remote_addr $consumer_name"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

key-auth: enable key authentication on the route.

key_type: set to var_combination to interpret the key is as a combination of variables.

key: set to $remote_addr $consumer_name to apply rate limiting quota by remote address and consumer.

Send a request as the consumer jane:

curl -i "http://127.0.0.1:9080/get" -H 'apikey: jane-key'

You should see an HTTP/1.1 200 OK response with the corresponding response body.

This request has consumed all the quota set for the time window. If you send the same request as the consumer jane within the same 30-second time interval, you should receive an HTTP/1.1 429 Too Many Requests response, indicating the request surpasses the quota threshold.

Send the same request as the consumer john within the same 30-second time interval:

curl -i "http://127.0.0.1:9080/get" -H 'apikey: john-key'

You should see an HTTP/1.1 200 OK response with the corresponding response body, indicating the request is not rate limited.

Send the same request as the consumer john again within the same 30-second time interval, you should receive an HTTP/1.1 429 Too Many Requests response.

This verifies the plugin rate limits by the combination of variables, remote_addr and consumer_name.

Share Quota among Routes

The following example demonstrates the sharing of rate limiting quota Among multiple routes by configuring the group of the limit-count plugin.

Note that the configurations of the limit-count plugin of the same group should be identical. To avoid update anomalies and repetitive configurations, you can create a service with limit-count plugin and upstream for routes to connect to.

Create a service:

curl "http://127.0.0.1:9180/apisix/admin/services" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "limit-count-service",
"plugins": {
"limit-count": {
"count": 1,
"time_window": 30,
"rejected_code": 429,
"group": "srv1"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

Create two routes and configure their service_id to be 1, so that they share the same configurations for the plugin and upstream:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "limit-count-route-1",
"service_id": "limit-count-service",
"uri": "/get1",
"plugins": {
"proxy-rewrite": {
"uri": "/get"
}
}
}'
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "limit-count-route-2",
"service_id": "limit-count-service",
"uri": "/get2",
"plugins": {
"proxy-rewrite": {
"uri": "/get"
}
}
}'
note

The proxy-rewrite plugin is used to rewrite the URI to /get so that requests are forwarded to the correct endpoint.

Send a request to route /get1:

curl -i "http://127.0.0.1:9080/get1"

You should see an HTTP/1.1 200 OK response with the corresponding response body.

Send the same request to route /get2 within the same 30-second time interval:

curl -i "http://127.0.0.1:9080/get2"

You should receive an HTTP/1.1 429 Too Many Requests response, which verifies the two routes share the same rate limiting quota.

Share Quota Among APISIX Nodes with a Redis Server

The following example demonstrates the rate limiting of requests across multiple APISIX nodes with a Redis server, such that different APISIX nodes share the same rate limiting quota.

On each APISIX instance, create a route with the following configurations. Adjust the address of the Admin API accordingly.

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "limit-count-route",
"uri": "/get",
"plugins": {
"limit-count": {
"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
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

policy: set to redis to use a Redis instance for rate limiting.

redis_host: set to Redis instance IP address.

redis_port: set to Redis instance listening port.

redis_password: set to the password of the Redis instance, if any.

redis_database: set to the database number in the Redis instance.

Send a request to an APISIX instance:

curl -i "http://127.0.0.1:9080/get"

You should see an HTTP/1.1 200 OK response with the corresponding response body.

Send the same request to a different APISIX instance within the same 30-second time interval, you should receive an HTTP/1.1 429 Too Many Requests response, verifying routes configured in different APISIX nodes share the same quota.

Share Quota Among APISIX Nodes with a Redis Cluster

You can also use a Redis cluster to apply the same quota across multiple APISIX nodes, such that different APISIX nodes share the same rate limiting quota.

Ensure that your Redis instances are running in cluster mode. A minimum of two nodes are required for the limit-count plugin configurations.

On each APISIX instance, create a route with the following configurations. Adjust the address of the Admin API accordingly.

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "limit-count-route",
"uri": "/get",
"plugins": {
"limit-count": {
"count": 1,
"time_window": 30,
"rejected_code": 429,
"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: set to redis-cluster to use a Redis cluster for rate limiting.

redis_cluster_nodes: set to Redis node addresses in the Redis cluster.

redis_password: set to the password of the Redis cluster, if any.

redis_cluster_name: set to the Redis cluster name.

redis_cluster_ssl: enable SSL/TLS communication with Redis cluster.

Send a request to an APISIX instance:

curl -i "http://127.0.0.1:9080/get"

You should see an HTTP/1.1 200 OK response with the corresponding response body.

Send the same request to a different APISIX instance within the same 30-second time interval, you should receive an HTTP/1.1 429 Too Many Requests response, verifying routes configured in different APISIX nodes share the same quota.

Rate Limit with Anonymous Consumer

The anonymous consumer is an Enterprise feature.

The following example demonstrates how you can configure different rate limiting policies by regular and anonymous consumers, where the anonymous consumer does not need to authenticate and has less quotas. While this example uses key-auth for authentication, the anonymous consumer can also be configured with basic-auth, jwt-auth, and hmac-auth.

Create a regular consumer john and configure the limit-count plugin to allow for a quota of 3 within a 30-second window:

curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "john",
"plugins": {
"limit-count": {
"count": 3,
"time_window": 30,
"rejected_code": 429
}
}
}'

Create the key-auth credential for the consumer john:

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"
}
}
}'

Create an anonymous user anonymous and configure the limit-count plugin to allow for a quota of 1 within a 30-second window:

curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "anonymous",
"plugins": {
"limit-count": {
"count": 1,
"time_window": 30,
"rejected_code": 429
}
}
}'

Create a route and configure the key-auth plugin to accept anonymous consumer anonymous from bypassing the authentication:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "key-auth-route",
"uri": "/anything",
"plugins": {
"key-auth": {
"anonymous_consumer": "anonymous"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

To verify, send five consecutive requests with john's key:

resp=$(seq 5 | xargs -I{} curl "http://127.0.0.1:9080/anything" -H 'apikey: john-key' -o /dev/null -s -w "%{http_code}\n") && \
count_200=$(echo "$resp" | grep "200" | wc -l) && \
count_429=$(echo "$resp" | grep "429" | wc -l) && \
echo "200": $count_200, "429": $count_429

You should see the following response, showing that out of the 5 requests, 3 requests were successful (status code 200) while the others were rejected (status code 429).

200:    3, 429:    2

Send five anonymous requests:

resp=$(seq 5 | xargs -I{} curl "http://127.0.0.1:9080/anything" -o /dev/null -s -w "%{http_code}\n") && \
count_200=$(echo "$resp" | grep "200" | wc -l) && \
count_429=$(echo "$resp" | grep "429" | wc -l) && \
echo "200": $count_200, "429": $count_429

You should see the following response, showing that only one request was successful:

200:    1, 429:    4

API7.ai Logo

API Management for Modern Architectures with Edge, API Gateway, Kubernetes, and Service Mesh.

Product

API7 Cloud

SOC2 Type IIISO 27001HIPAAGDPRRed Herring

Copyright © APISEVEN Ltd. 2019 – 2024. Apache, Apache APISIX, APISIX, and associated open source project names are trademarks of the

Apache Software Foundation