言成言成啊 | Kit Chen's Blog

Nginx限流实践

发布于2024-12-07 19:38:40,更新于2024-12-07 22:06:06,标签:devops  文章会持续修订,转载请注明来源地址:https://meethigher.top/blog

一、限流

之前我有记录通过CentOS7定时任务实现的Nginx限流功能。这算是通过Nginx进行限流的一种思路。

还有另外一种思路,是通过Nginx内置的两个模块来实现。

  • limit_req: 用于限制每秒的请求次数。该模块基于令牌桶(Token Bucket)算法,每个请求在处理前必须从令牌桶中获取一个令牌,如果没有令牌可用,则请求被延迟或拒绝。
  • limit_conn: 用于限制同时连接数。该模块控制每个特定键(如IP地址或用户)允许的最大并发连接数。

1.1 limit_req

若需要查看详细内容,自行查阅Module ngx_http_limit_req_module

limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;定义一个10MB的内存区域,命名为one,用来存储客户端IP地址的调用数,限制每个客户端每秒只能调用1次。注意nginx是以毫秒为单位的。当配置了2r/s时,平均下来就是每500ms内,只允许成功1个请求。

limit_req zone=one burst=5 nodelay;使用one空间,限制同一个键调用时,支持5个突发请求,并且配置nodelay表示立即响应。

limit_req可以配置在http、server、location内。

若未配置nodelay,则表示进行延迟处理,当超过请求速率rate时,多余的请求会进入突发队列(长度由 burst 决定)。Nginx 会根据配置的rate,以固定时间间隔从队列中取出请求进行处理。例如:

  • rate=1r/s 意味着每 1000ms 处理一个请求。
  • 如果一个客户端在 1 秒内发送了 6 个请求:
    • 前 1 个请求按速率直接处理。
    • 剩下的 5 个请求将进入突发队列并被延迟。
    • 每隔 1000ms,处理队列中的一个请求,持续 5000ms。

当未配置nodelay时,持续 5000ms 会间接影响到后续的在rate内请求的响应速率。

配置示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
worker_processes 2;
error_log logs/error.log;
events {
worker_connections 4096;
}

http {
include mime.types;
default_type application/octet-stream;
log_format main
'$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log logs/access.log main;
sendfile on;

limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
limit_req_status 429;


server {
listen 80;

location / {
limit_req zone=one burst=5 nodelay;
root html;
}
}
}

以上示例,在高并发调用时,实际情况前6次立马成功,后续每隔1秒成功1个请求,其他请求均返回429状态码。该结果可以使用JMeter来进行验证。

1.2 limit_conn

若需要查看详细内容,自行查阅Module ngx_http_limit_conn_module

limit_conn_zone $binary_remote_addr zone=two:10m;定义一个10MB的内存区域,命名为two,用来存储客户端IP地址的连接数。

limit_conn two 1;使用two空间,限制同一个键,同时刻最多只有1个连接。

准备一个10秒才会响应的后端服务http://10.0.0.1:4321

示例配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
worker_processes 2;
error_log logs/error.log;
events {
worker_connections 4096;
}

http {
include mime.types;
default_type application/octet-stream;
log_format main
'$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log logs/access.log main;
sendfile on;


limit_conn_zone $binary_remote_addr zone=two:10m;
limit_conn_status 409;


server {
listen 80;

location / {
limit_conn two 1;
proxy_pass http://10.0.0.1:4321;
}
}
}

以上示例,在1000个请求连接时,只有1个连接成功,其他请求均返回409状态码。该结果可以使用JMeter来进行验证。

二、参考

Module ngx_http_limit_req_module

Module ngx_http_limit_conn_module

Nginx限流功能优化:让流量控制变得轻松简单

发布:2024-12-07 19:38:40
修改:2024-12-07 22:06:06
链接:https://meethigher.top/blog/2024/nginx-limit-flow/
标签:devops 
付款码 打赏 分享
Shift+Ctrl+1 可控制工具栏