Nginx原生提供限流功能,能有效保护服务器资源,防止恶意攻击和过度请求。
1.限流算法
主要有三种限流算法:固定窗口算法、漏桶算法和令牌桶算法。
1.1.固定窗口算法(ngx_http_limit_req_module)
允许你定义一个请求速率(例如每秒允许的请求数量)和一个时间窗口。当请求到达时,Nginx会检查在当前的时间窗口内是否已经达到了设置的速率限制。如果请求超出了速率限制,Nginx可以配置为返回错误状态码(如503 Service Temporarily Unavailable)或者延迟处理请求。
固定窗口算法主要通过limit_req_zone和limit_req指令来实现。limit_req_zone指令用于定义限流区域和相关参数,而limit_req指令则用于在特定的location或server块中启用限流。
1.2.漏桶算法(ngx_http_limit_conn_module)
漏桶算法是一种流量整形(Traffic Shaping)和流量控制(Rate Limiting)算法。它限制了同时处理的连接数,可以用来限制对某个资源(如服务器、数据库等)的并发访问数。当达到限制的连接数时,新的连接会被拒绝,直到现有的连接数降低。
漏桶算法主要通过limit_conn_zone和limit_conn指令来实现。limit_conn_zone指令用于定义连接限制区域和相关参数,而limit_conn指令则用于在特定的location或server块中启用连接限制。
1.3.令牌桶算法(ngx_http_limit_req_module)
令牌桶算法是一种更为复杂的限流算法。它通过固定速率向桶中添加令牌。每个请求都需要消耗一个令牌才能被处理。如果桶中有足够的令牌,请求将立即被处理;如果没有令牌,则请求可以被延迟处理或拒绝。这种算法允许一定程度的突发流量,因为桶中可以积累令牌以应对短时间内的请求峰值。
虽然ngx_http_limit_req_module模块本身并不直接实现令牌桶算法,但可以通过结合limit_req_zone、limit_req以及burst和nodelay参数来模拟令牌桶算法的行为。burst参数定义了当请求超过速率限制时,允许的最大请求数(即桶的容量),而nodelay参数则决定了是否立即处理超过速率的请求。
2.限流实现
Nginx的限流功能主要通过limit_req和limit_conn模块实现。
如果要使用Nginx限流,则需要做到以下两步:
(1)首先,要启用请求限速模块,确保nginx已经编译并启用了limit_req和limit_conn模块,nginx默认是开启的,因此确认编译的时候没有通过--without-http_limit_req_module和--without-http_limit_conn_module关闭这两个模块。
(2)然后,在nginx的配置文件中设置请求限速规则,通过使用limit_req_zone指令来定义请求限速的共享内存区域。该指令指定了限速的区域名称、存储限速状态的内存大小以及限速的参数。
3.限流配置
包含两种不同的模块配置。
3.1.limit_req限流配置
limit_req模块用于限制每秒的请求次数。该模块基于令牌桶(Token Bucket)算法,每个请求在处理前必须从令牌桶中获取一个令牌,如果没有令牌可用,则请求被延迟或拒绝。
limit_req模块通过定义共享内存区域来存储限流信息,并在特定的上下文中应用限流策略。
3.1.1.定义共享内存区域
首先,需要定义一个共享内存区域来存储请求的计数信息。可以使用limit_req_zone指令来完成。语法如下:
limit_req_zone $variable zone={name}:{size} rate={rate};
例如
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
这里,$binary_remote_addr表示的客户端IP地址。
zone=one:10m表示定义名为one的共享内存区域,大小为10MB。
rate=1r/s表示限制每秒最多1个请求。
3.1.2.应用限流策略
在定义共享内存区域后,可以在server或location上下文中使用limit_req指令来应用限流策略。
配置格式如下
limit_req zone={name} [burst={number}] [nodelay];
其中,zone={name}指定使用名的共享内存区域。
burst={number}指定允许突发请求的个数。
nodelay表示立即处理突发请求,不进行延迟。
3.1.3.示例配置详解
以下是一个完整的示例配置:
http {
# 定义共享内存区域
limit_req_zone $binary_remote_addr zone=one:20m rate=3r/s;
server {
listen 7788;
server_name abc.com;
location / {
# 应用限流策略
limit_req zone=one burst=10 nodelay;
# 代理到后端服务器
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
这个示例中,Nginx会限制每个客户端每秒最多发送3个请求,并允许最多10个突发请求。
3.2.limit_conn限流配置
limit_conn模块用于限制同时连接数。该模块控制每个特定键(如IP地址或用户)允许的最大并发连接数。
3.2.1.定义共享内存区域
这里也需要定义一个共享内存区域来存储连接计数信息。可以使用limit_conn_zone指令来完成。语法如下:
limit_conn_zone $variable zone={name}:{size};
$binary_remote_addr表示的客户端IP地址。
zone={name}:{size}定义共享内存区域的名称,并指定内存大小。
3.2.2.应用限流策略
在定义共享内存区域后,可以在server或location上下文中使用limit_conn指令来应用限流策略。语法如下:
limit_conn {zone_name} {number};
{zone_name}指定使用的共享内存区域名称。
{number}表示允许的最大并发连接数。
3.2.3.示例配置详解
以下是一个完整的示例配置:
http {
# 定义共享内存区域
limit_conn_zone $binary_remote_addr zone=addr:20m;
server {
listen 80;
server_name example.com;
location / {
# 应用限流策略
limit_conn addr 20;
# 代理到后端服务器
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
示例中,Nginx会限制每个客户端最多允许20个并发连接。