Nginx 作为一个高性能的 Web 服务器和反向代理服务器,不仅可以提供负载均衡、SSL 加密、缓存等功能,还支持强大的请求限流功能。请求限流(Rate Limiting)用于限制客户端在单位时间内能够发起的请求数,防止恶意请求(如 DDoS 攻击)和流量过载。
Nginx 提供了多种方式来实现 请求限流控制(Rate Limiting),用于控制客户端在一定时间内对服务器的请求频率。限流控制有助于防止恶意攻击(如暴力破解、DDoS 攻击)以及过多的请求导致服务器负载过高。
请求限流的概念
请求限流是一种流量控制机制,用于限制每个客户端在指定时间内对服务器发起的请求数量。常见的应用场景包括:
- 防止暴力破解:限制用户短时间内的登录请求次数。
- 防止 DDoS 攻击:减少恶意请求对服务器资源的消耗。
- 流量调控:控制每个用户的访问频率,防止某个用户消耗过多资源。
Nginx 支持两种主要的限流方法:基于请求频率的限流和基于连接数的限流。下面将详细介绍这些方法,并给出配置示例。
请求频率限制(Request Rate Limiting)
Nginx 提供了 limit_req_zone
和 limit_req
指令来基于客户端的请求频率进行限流。
配置步骤
limit_req_zone
:定义一个共享内存区域用于存储客户端请求的状态,通常基于客户端的 IP 地址($binary_remote_addr
)来进行区分。limit_req
:在location
块内应用该规则,限制某个特定路径或资源的请求频率。
限制每个 IP 每秒最多 1 个请求
# 定义一个名为 req_limit_per_ip 的共享内存区域,大小为 10MB,用于存储每个客户端的请求信息
# rate=1r/s 表示每个客户端每秒最多只能发送 1 个请求
limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=1r/s;
server {
listen 80;
server_name example.com;
# 应用限流规则:每秒最多允许 1 次请求,超过会返回 503 错误
location / {
# 限制每个客户端的请求频率为每秒 1 次
# burst=5 允许最多 5 个突发请求
# nodelay 表示如果请求超过限制但仍在 5 个突发请求内,Nginx 不会延迟处理请求
limit_req zone=req_limit_per_ip burst=5 nodelay;
proxy_pass http://backend;
}
}
配置解释:
rate=1r/s
:每秒最多允许 1 次请求。burst=5
:允许请求的突发请求数,超出 5 次的请求会被限制。nodelay
:表示如果请求频率超过限制但仍在突发请求数内,Nginx 不会延迟响应。
连接数限制(Connection Limiting)
除了限制请求频率外,Nginx 还可以限制每个客户端的连接数。这对于防止某个客户端过多的并发连接导致资源耗尽非常有用。
配置步骤
limit_conn_zone
:定义一个共享内存区域,用来存储连接信息。limit_conn
:在location
块中应用连接数限制规则。
限制每个 IP 同时最多 1 个连接
# 定义了一个名为 conn_limit_per_ip 的共享内存区域,大小为 10MB,用于存储客户端连接信息
limit_conn_zone $binary_remote_addr zone=conn_limit_per_ip:10m;
server {
listen 80;
server_name example.com;
location / {
# 限制每个 IP 最多只能有 1 个并发连接
limit_conn conn_limit_per_ip 1;
proxy_pass http://backend;
}
}
配置解释:
limit_conn_zone $binary_remote_addr
:基于客户端的 IP 地址进行限制。limit_conn conn_limit_per_ip 1
:限制每个客户端最多同时拥有 1 个连接。
综合限流与连接限制
你也可以将请求速率限制和连接数限制结合起来,进行更精细的流量控制。例如,限制每个 IP 每秒请求数,并且限制每个 IP 同时可以保持的连接数。
请求频率和连接数同时限制
# 请求频率限制:每秒最多 1 次请求
limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=1r/s;
# 连接数限制:每个 IP 地址最多 1 个连接
limit_conn_zone $binary_remote_addr zone=conn_limit_per_ip:10m;
server {
listen 80;
server_name example.com;
# 限制每个 IP 每秒最多 1 次请求,允许最多 5 个突发请求
location / {
limit_req zone=req_limit_per_ip burst=5 nodelay;
limit_conn conn_limit_per_ip 1;
proxy_pass http://backend;
}
}
配置解释:
limit_req_zone
:限制请求频率为每秒 1 次。limit_conn_zone
:限制每个 IP 地址最多只能有 1 个连接。limit_req
:每秒最多 1 次请求,允许 5 个突发请求。limit_conn
:每个 IP 地址最多只能同时保持 1 个连接。
返回定制化错误页面
在限制请求后,Nginx 可以返回一个定制的错误页面,而不是默认的 503 错误。你可以使用 error_page
指令来实现。
定制 503 错误页面
server {
listen 80;
server_name example.com;
# 限制请求频率,每秒最多 1 次
location / {
limit_req zone=req_limit_per_ip burst=5 nodelay;
proxy_pass http://backend;
}
# 自定义 503 错误页面
error_page 503 /custom_503.html;
location = /custom_503.html {
root /var/www/html;
internal;
}
}
配置解释:
error_page 503 /custom_503.html;
:当请求超过限制时,Nginx 会返回 503 错误,并显示custom_503.html
页面。location = /custom_503.html
:定义一个内部页面/custom_503.html
,用于展示定制的错误页面。
限流日志
你可以启用 Nginx 的访问日志,记录被限流的请求,以便后续分析。可以通过设置 log_format
来记录请求信息,并通过日志分析工具来监控限流情况。
记录限流日志
log_format limit_log '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
server {
listen 80;
server_name example.com;
access_log /var/log/nginx/limit_requests.log limit_log;
location / {
limit_req zone=req_limit_per_ip burst=5 nodelay;
proxy_pass http://backend;
}
}
配置解释:
log_format limit_log
:定义了一个自定义的日志格式,记录请求的详细信息。access_log /var/log/nginx/limit_requests.log limit_log;
:将限流请求的日志记录到/var/log/nginx/limit_requests.log
文件中。
限流的实践与优化
- 设置合适的限流速率:根据业务需求,合理设置请求的限流速率。例如,对于登录系统,可以限制每个用户每分钟最多 5 次尝试登录;而对于静态资源的请求,可以设置更高的请求频率。
- 针对不同路径设置不同的限流策略:对于敏感资源(如登录、支付等)进行更严格的限流,而对于静态资源则可以设置较宽松的限制。
- 动态调整限流策略:根据服务器负载情况,动态调整请求频率或连接数限制。例如,可以根据系统资源的使用情况自动调整限流参数,保证服务器不被过载。
- 监控与报警:配合监控工具(如 Prometheus、Grafana)监控 Nginx 的限流效果,及时发现异常请求行为并报警。