从零开发短视频电商 利用Nginx限流保护应用安全

基础

nginx配置文件结构图

main #全局设置
events { ... }
http{
   upstream #负载均衡服务器设置
   server{ #主机设置
        location  { #URL匹配设置
            ... 
        }
    }
}

server继承main,location继承server,upstream即不会继承其他设置也不会被继承。

Nginx查看安装版本
# nginx -v
nginx version: nginx/1.20.1
Nginx配置了哪些模块
# nginx -V
nginx version: nginx/1.20.1
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)
built with OpenSSL 1.1.1k  25 Mar 2021
TLS SNI support enabled
configure arguments: --user=www --group=www --prefix=/www/server/nginx --add-module=srclib/ngx_devel_kit --add-module=srclib/lua_nginx_module --add-module=srclib/ngx_cache_purge --add-module=srclib/nginx-sticky-module --with-openssl=srclib/openssl --with-pcre=srclib/pcre-8.43 --with-http_v2_module --with-stream --with-stream_ssl_module --with-stream_ssl_preread_module --with-http_stub_status_module --with-http_ssl_module --with-http_image_filter_module --with-http_gzip_static_module --with-http_gunzip_module --with-ipv6 --with-http_sub_module --with-http_flv_module --with-http_addition_module --with-http_realip_module --with-http_mp4_module --with-ld-opt=-Wl,-E --with-cc-opt=-Wno-error --with-http_dav_module --add-module=srclib/nginx-dav-ext-module

限流配置

Nginx提供几种限流方式。

  • 请求速率控制,限制单个IP的请求处理速率
  • 并发连接数控制,限制单个IP连接数,server的总连接数
  • 每个连接的下载速度

以上3种限流方式可以搭配结合使用,在指定的server或者location上限流。

请求限制QPS

ngx_http_limit_req_module 模块提供限制请求处理速率能力,使用了漏桶算法(leaky bucket),限制单个IP的请求处理速率。

  • 漏桶算法

    img

    • 作用:保证数据的最大的传输速率,桶的出口滴水速度恒定;不能应对突发流量,突发流量直接溢出丢弃
  • 令牌桶算法

    img

    • 作用:能够限制数据的平均传输速率外,还允许某种程度的突发传输。

适用场景:如果要让自己的系统不被打垮,用令牌桶。如果保证别人的系统不被打垮,用漏桶算法

示例如下

先在http范围定义一个limit_req_zone,然后在server或者location范围使用它。

http {
    # 定义了一个ip_limit缓冲区(容器),同一个IP请求频率为每秒10个请求(r/s)
	limit_req_zone $binary_remote_addr zone=ip_limit:10m rate=10r/s; 
	server {
        ...
  		location /login {
    		limit_req zone=ip_limit burst=12 nodelay;
    		proxy_pass http://login_upstream;
  		}
	}
}
  • limit_req_zone 只能配置在 http 范围内;
  • $binary_remote_addr 客户端请求的IP地址,表示基于 remote_addr(客户端IP) 来做限流,binary_ 的目的是压缩内存占用量。;
  • zone=ip_limit:10m 自己定义限流规则名称为ip_limit,允许使用**10MB(存储16W个IP)**的内存空间来记录ip对应的限流状态;
    • 官方给出1M的缓存空间可以在 32位的系统中服务 3.2万IP地址,在 64 位的系统中可以服务 1.6万IP地址。不够的话自己加大点。
    • 当NGINX需要添加新的记录时,如果此时存储耗尽了,最老的记录会被移除。如果释放的存储空间还是无法容纳新的记录,NGINX返回**503 (Service Temporarily Unavailable)**状态码。此外,为了防止内存被耗尽,每次NGINX创建一个新的记录的同时移除多达两条前60秒内没有被使用的记录。
  • rate=10r/s 限流速度为每秒10次请求,实际上是按毫秒计算, 即每 1次/100ms
    • 每100毫秒处理一个请求。这意味着,自上一个请求处理完后,若后续100毫秒内又有请求到达,将拒绝处理该请求。
  • burst=12 漏桶的大小设置为12 是FIFO队列,把得不到执行的请求暂时缓存起来。
  • nodelay 配合burst使用,要么立刻执行,要么被拒绝,请求不会因为限流而增加延迟了。
  • location /login 仅仅对登录接口进行限流,如果放在server下,即对整个server限流。
并发限制连接数

ngx_http_limit_conn_module 提供了限制连接数的能力。

示例如下

先在http范围定义一个limit_conn_zone,然后在server或者location范围使用它。

http {
    limit_conn_zone $binary_remote_addr zone=perip:10m;
    limit_conn_zone $server_name zone=perserver:10m;
	server {
    		...
        	# 每个IP只允许一个连接
        	limit_conn perip 10;
          	# 限制服务器的总连接数
        	limit_conn perserver 100;      
        	# 限制传输速度(如果有N个并发连接,则是 N * limit_rate)
        	limit_rate 1024k;
	}
}
  • limit_conn_zone 只能配置在 http 范围内;

  • $binary_remote_addr 表示客户端请求的IP地址;

  • $server_name 表示虚拟主机(server) 同时能处理并发连接的总数;

  • limit_conn perip 10 表示限制单个IP同时最多能持有10个连接;

  • limit_conn perserver 100 表示虚拟主机(server) 同时能处理并发连接的总数;

  • limit_rate 1024k 限制单个连接传输速度,如果有N个并发连接,则是 N * limit_rate

下载速度限制带宽

ngx_http_core_module 还提供了限制数据传输速度的能力(即常说的下载速度)。

例如:

location / {
	...
    limit_rate_after 20m;
    limit_rate       100k;
}

这个限制是针对每个请求的,表示客户端下载前20M时不限速,后续限制100kb/s。

被限制后发送给客户端的错误码

默认,当某个客户端超过它的限流,NGINX用503(Service Temporarily Unavailable)状态码来响应。使用limit_req_status指令设置一个不同的状态码(在下面的例子是444):

location /login {
      limit_req zone=mylimit burst=20 nodelay;
      limit_req_status 444;
}
拒绝对特定位置的所有请求

如果你想拒绝对于某个特定URL的所有请求,而不是仅仅的限制它们。

location /buyer {
      deny all;
}
限流日志

默认,NGNIX记录由于限流导致的延迟或丢弃的请求的日志,如下面的例子:

2015/06/13 04:20:00 [error] 120315#0: *32086 limiting requests, excess: 1.000 by zone "lakerlimit", client: 192.168.1.2, server: nginx.com, request: "GET / HTTP/1.0", host: "nginx.com"

该日志记录包含的字段:

  • limiting requests — 日志条目记录了某个限流的标志
  • excess — 超过这个请求代表的配置的速率的每毫秒请求数目
  • zone — 定义了启用了限流的区域
  • client — 产生请求的客户端IP地址
  • server — 服务器的IP地址或主机名
  • request — 客户端产生的实际的HTTP请求
  • host — HTTP头部主机名的值

默认,NGINX日志在error级别拒绝请求,如上面例子中的**[error]所示。(它在低一个级别上记录延迟的请求,因此默认是info**。)用limit_req_log_level指令来改变日志级别。

limit_conn_log_level info | notice | warn | error;

下面我们设置在warn级别上记录被拒绝的请求的日志:

location /login {
      limit_req zone=mylimit burst=20 nodelay;
      limit_req_log_level warn;
}
黑白名单限流

白名单不限量,黑名单上的IP进行限流。

geo $limit {
        default 1;
        10.0.0.0/8 0;
        192.168.0.0/24 0;
}
map $limit $limit_key {
        0 "";
        1 $binary_remote_addr;
}
limit_req_zone $limit_key zone=req_zone:10m rate=5r/s;
server {
        location / {
                limit_req zone=req_zone burst=10 nodelay;           
                # ...
        }
}

这个例子同时使用了geomap指令。对于IP地址在白名单中的,geo块分配0值给$limit;其它所有不在白名单中的IP地址,分配1值。然后我们使用一个map去将这些值映射到某个key中,例如:

  • 如果$limit0$limit_key被设置为空字符串
  • 如果$limit1$limit_key被设置为客户端的IP地址的二进制格式

这个两个结合起来,对于白名单中的IP地址,$limit_key被设置为空字符串;否则,被设置为客户端的IP地址。当limit_req_zone指令的第一个参数是一个空字符串,限制不起作用,因此白名单的IP地址(在10.0.0.0/8和192.168.0.0/24子网中)没有被限制。其它所有的IP地址都被限制为5个请求每秒。

limit_req指令将限制作用在/定位中,并且允许在没有转发延迟的情况下,转发多达10个数据包。

限流整体示例
http {
    #限制每个uri请求速率
    limit_req_zone $uri zone=api_read:20m rate=50r/s;
    #限制并发数
    #按ip配置一个连接 zone
    limit_conn_zone $binary_remote_addr zone=perip_conn:10m;
    #按server配置一个连接 zone
    limit_conn_zone $server_name zone=perserver_conn:100m;
    server {
         #请求限流排队通过 burst默认是0
 		 limit_req zone=api_read burst=100 nodelay;
         #连接数限制,每个IP并发请求为50
         limit_conn perip_conn 50;
         #服务所限制的连接数(即限制了该server并发连接数量)
         limit_conn perserver_conn 200;
         #连接限速
         limit_rate 512k;
    }
}

参考

  • http://nginx.org/en/docs/http/ngx_http_limit_req_module.html

  • http://nginx.org/en/docs/http/ngx_http_limit_conn_module.html

  • https://chenyongjun.vip/articles/81

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lakernote

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值