NGINX 中的速率限制是控制服务器处理的流量的重要功能。它有助于保护您的服务器免受短时间内过多请求的困扰,而恶意攻击(如 DDoS 或高流量峰值)可能会导致这种情况。实施速率限制可确保您的资源得到有效利用,并且合法用户可以不间断地访问您的服务。
本指南将演示如何在 NGINX 中配置速率限制,并提供清晰的说明来帮助您有效地管理和控制传入流量。
理解 NGINX 中的速率限制指令
NGINX 速率限制关键指令
NGINX 使用特定指令配置速率限制,每个指令都有独特的功能:
- 限制请求区域: NGINX 中的 limit_req_zone 指令设置了一个共享内存区域,用于存储速率限制信息。它位于 http 上下文中,确定允许的请求速率,有效地设置了速率限制的基准。
- 限制请求: 在位置上下文中使用的 limit_req 指令强制执行 limit_req_zone 设置的速率限制。它将这些限制应用于特定位置或 URL,从而控制对这些端点的访问频率。
- 限制请求状态: limit_req_status 指令位于 location 上下文中,指定请求率超出限制时返回的 HTTP 状态代码。此反馈机制对于在超出允许的请求频率时通知用户或自动化系统至关重要。
创建速率限制配置
要在 NGINX 中实现速率限制,请在 NGINX 配置文件中插入适当的指令。考虑这个基本示例:
http {
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=5r/s;
server {
...
location / {
limit_req zone=mylimit burst=10;
...
}
}
}
在此配置中,limit_req_zone 指令会建立一个名为“mylimit”的内存区域,允许每个客户端 IP 地址 ($binary_remote_addr) 每秒发出 5 个请求 (5r/s)。然后,limit_req 指令会将此速率限制应用于根位置 (/),突发容量为 10 个请求,在严格速率限制和合法流量高峰的灵活性之间取得平衡。
NGINX 中的速率限制:实际示例
基本速率限制配置
本节将探讨 NGINX 中应用于服务器范围的基本速率限制配置。目的是限制用户对服务器的请求,确保稳定的性能并降低过载风险。
示例:服务器范围的速率限制
考虑以下 NGINX 配置:
http {
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=2r/s;
server {
listen 80;
server_name example.com;
location / {
limit_req zone=mylimit burst=5;
proxy_pass http://backend;
}
}
}
此配置为每个客户端设置每秒 2 个请求的限制,由其 IP 地址定义($binary_remote_addr
)让我们分解一下关键组件:
- 限制请求区域:定义一个内存区域 (mylimit),用于存储速率限制状态,大小为 10 MB。它将速率限制设置为每秒 2 个请求 (2r/s)。
- 服务器块:在端口 80 上监听到 example.com 的传入流量。
- 位置块:将速率限制应用于根 URL (/)。burst 参数允许最多 5 个请求的突发,为流量的短暂高峰提供灵活性。proxy_pass 指令将请求转发到指定的后端服务器。
- 突发参数:limit_req 指令中的 burst=5 设置允许短期内增加请求,最多可增加 5 个超出设定速率的请求。此功能对于处理突然、合法的流量增加而不影响用户体验至关重要。
- 代理通行证:proxy_pass http://backend; 指令将流量转发到后端服务器。这通常用于负载平衡场景或 NGINX 充当反向代理时。
高级速率限制示例
不同地点有不同的速率限制
在更复杂的场景中,您可能需要对不同的应用程序部分应用不同的速率限制。当特定端点资源密集度更高或容易被滥用时,这尤其有用。
考虑以下配置:
http {
limit_req_zone $binary_remote_addr zone=low:10m rate=1r/s;
limit_req_zone $binary_remote_addr zone=high:10m rate=10r/s;
server {
listen 80;
server_name example.com;
location /api/low {
limit_req zone=low burst=3;
proxy_pass http://backend;
}
location /api/high {
limit_req zone=high burst=20;
proxy_pass http://backend;
}
}
}
此配置对 /api/low 位置应用较低的速率限制(每秒 1 个请求),对 /api/high 位置应用较高的速率限制(每秒 10 个请求)。
其他 Nginx 速率限制示例
根据请求类型进行速率限制
您可以根据特定请求(例如 GET、POST 或 PUT 请求)配置速率限制。当您想要保护更容易受到滥用或对服务器资源影响更大的特定端点时,此功能特别有用。
您可以使用 if 指令和 $request_method 变量将速率限制应用于特定请求类型。以下是示例:
http {
limit_req_zone $binary_remote_addr zone=get_limit:10m rate=5r/s;
limit_req_zone $binary_remote_addr zone=post_limit:10m rate=2r/s;
server {
listen 80;
server_name example.com;
location / {
if ($request_method = GET) {
limit_req zone=get_limit burst=10;
}
if ($request_method = POST) {
limit_req zone=post_limit burst=5;
}
proxy_pass http://backend;
}
}
}
在此配置中,我们设置了两个单独的速率限制:一个用于 GET 请求(每秒 5 个请求),一个用于 POST 请求(每秒 2 个请求)。
基于用户代理的速率限制
另一个有用的技巧是根据客户端发送的 User-Agent 标头应用速率限制。这可以帮助保护您的服务免受导致问题的特定机器人或爬虫的攻击。
要实现基于 User-Agent 的速率限制,您可以使用 map 指令和 $http_user_agent 变量。
以下是一个例子:
http {
map $http_user_agent $limit_bots {
default 0;
~*(Googlebot|Bingbot) 1;
}
limit_req_zone $binary_remote_addr zone=bot_limit:10m rate=1r/s;
server {
listen 80;
server_name example.com;
location / {
if ($limit_bots) {
limit_req zone=bot_limit burst=2;
}
proxy_pass http://backend;
}
}
}
在此示例中,我们定义了一个 map 指令,如果 User-Agent 标头与“Googlebot”或“Bingbot”匹配,则将 $limit_bots 变量设置为 1。然后,我们对来自这些机器人的请求应用每秒 1 个请求的速率限制。
将 IP 列入速率限制白名单
有时,您可能希望免除特定 IP 地址(例如受信任的合作伙伴或内部服务)的速率限制。为此,您可以使用 geo 指令以及 if
指示。
以下是一个例子:
http {
geo $rate_limit {
default 1;
192.168.0.0/24 0;
10.0.0.0/8 0;
}
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=5r/s;
server {
listen 80;
server_name example.com;
location / {
if ($rate_limit) {
limit_req zone=mylimit burst=10;
}
proxy_pass http://backend;
}
}
}
分布式环境中的扩展速率限制
当多个 Nginx 实例在分布式环境中运行时,您可能希望确保所有实例的速率限制一致。您可以使用 Redis 等集中式数据存储来管理速率限制,以实现此目的。这样做可以让您维护所有 Nginx 实例之间共享的全局速率限制。
要使用 Redis 设置速率限制,您必须安装并配置 nginx-module-redis 模块。安装模块后,您可以更新 Nginx 配置以使用 Redis 进行速率限制。
以下是一个例子:
load_module modules/ngx_http_redis_module.so;
http {
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=5r/s;
upstream redis_server {
server 127.0.0.1:6379;
keepalive 32;
}
server {
listen 80;
server_name example.com;
location / {
limit_req_redis zone=mylimit burst=10 redis_server=redis_server;
proxy_pass http://backend;
}
}
}
在此示例中,我们为 Redis 服务器定义了一个上游块,并更新了位置块以使用 limit_req_redis 指令而不是标准 limit_req 指令。此配置可确保使用共享 Redis 数据存储强制执行速率限制,从而在多个 Nginx 实例之间提供一致的速率限制。
动态速率限制
在某些情况下,您可能希望根据某些条件或服务器的当前负载动态调整速率限制。例如,您可能希望在高峰流量时段应用更严格的速率限制,以更好地管理服务器资源。
要实现动态速率限制,您可以使用 map
指令根据特定条件定义速率限制。
以下是一个例子:
http {
map $http_x_traffic $dynamic_rate {
default "5r/s";
high "2r/s";
}
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=$dynamic_rate;
server {
listen 80;
server_name example.com;
location / {
limit_req zone=mylimit burst=10;
proxy_pass http://backend;
}
}
}
在此配置中,我们使用从自定义标头 X-Traffic 派生的 $http_x_traffic 变量。根据此标头的值,我们动态设置速率限制。当标头值为“high”时,我们会应用更严格的速率限制,即每秒 2 个请求。否则,我们使用默认速率,即每秒 5 个请求。
请注意,此示例假设您的后端服务器或基础设施中的其他组件根据您期望的条件设置 X-Traffic 标头。
在 NGINX 配置中测试速率限制
使用 curl 验证速率限制
使用 curl 进行简单请求测试
为了验证 NGINX 中速率限制设置的有效性,curl(用于发送 HTTP 请求的命令行工具)非常有用。它可以快速向您的服务器发送多个请求,帮助您评估速率限制是否有效。
for i in {1..10}; do curl -I http://example.com; done
- 此命令向您的服务器发出 10 个 HEAD 请求,目标为 http://example.com。
- 分析这些请求的 HTTP 响应标头以验证速率限制功能。
- 当请求率超过您指定的限制时,NGINX 应该返回 429 请求过多状态代码。
使用 Apache Bench (ab) 进行测试
使用 Apache Bench 对服务器响应进行基准测试
Apache Bench (ab) 是一款有效的基准测试工具,非常适合通过模拟高流量条件来测试速率限制。它有助于了解 NGINX 服务器在请求激增的情况下的表现。
ab -n 100 -c 10 http://example.com/
- 此命令指示 ab 以并发级别 10 向 http://example.com 发送 100 个请求。
- ab 的输出提供了对限速有效性的见解。
- 关注输出中失败请求的数量,这应该与 NGINX 速率限制配置的设置一致。
采用最佳方法测试您的 NGINX 配置可确保您的速率限制规则按预期运行。
结论
通过在 NGINX 中配置速率限制,您可以保护服务器免受过多流量和潜在滥用的影响。这有助于维护服务的性能和可用性,确保合法用户获得更好的体验。定期监控和调整速率限制设置以平衡安全性和可访问性。实施这些控制对于有效管理服务器资源至关重要。