服务高可用保障:服务限流,Nginx实现服务限流

一、前言

1.1什么是限流?

限流存在于高可用服务中。
用于高可用的保护手段,主要包括:缓存,降级,限流
限流:只允许指定的事件进入系统,超过的部分将被拒绝服务,排队或者降级处理。

1.2为什么需要限流?

一:服务扛不住压力了
二:因为资源的稀缺或者处于安全防范的目的而采用的自我保护机制,保证有限的资源提供最大的服务能力,按照预期的流量提供服务 ,超过的部分将会拒绝服务,排队或者降级处理

二、按照限流算法分类

2.1.计数器(固定窗口计数器)

通用及最简单的算法,简单逻辑是维护一个固定时间的计数器,如果检测到单位时间过去则记为0,重新计数
服务高可用保障:服务限流,Nginx实现服务限流_第1张图片

存在的问题
1.没有应对突发的流量的能力:如100的qps,前100ms来了99个,后900ms只能处理一个
2.不准确,在一个窗口内后半段时间来了100个请求,以及在后一个窗口的前半段时间100个请求,等同于在一个窗口内出现了双倍的限流的流量!

2.2 漏铜算法

服务高可用保障:服务限流,Nginx实现服务限流_第2张图片

水:请求
桶:限流阈值大小
漏的水滴:固定速率,服务的处理速度
实现步骤:
1.将每个请求放入固定的大小的队列进行存储
2.以固定的速率向外流出请求,队列为空则停止流出
3.队列满了则拒绝服务

2.3令牌桶算法

服务高可用保障:服务限流,Nginx实现服务限流_第3张图片

为了保证网站在遭受流量攻击的时候,仍然能够保障正常用户的访问不受到影响,有必要对网站添加限流措施。通过简单的配置Nginx,可以帮助我们实现这一功能。
优点:令牌桶支持突发流量
因为桶中有多少令牌在等待,就允许有多少突发请求可以执行

实现步骤:
1.以恒定的速率向桶中增加令牌
2.如果令牌满了直接丢弃,如果有请求则获取令牌进行请求
3.如果桶空了,则拒绝执行

三、Nginx实现服务限流

实现服务限流的方式有很多种,下面我主要介绍的是Nginx实现,优点是不用频繁部署jar服务,减少代码编写。提高效率,短时间解决问题

Nginx支持通过以下维度,来对用户的请求进行限制:

  1. 控制访问频率
  2. 控制并发连接数
  3. 控制访问速率
  4. IP黑白名单

3.1超过访问频率就立即拒绝

对应Nginx模块:ngx_http_limit_req_module

# 限流设置,这只是设置流量限制和共享内存区域的参数,但实际上并不限制请求速率。具体的限制需要定义具体的url
limit_req_zone $binary_remote_addr zone=contentRateLimit:10m rate=10r/s;
# 指定错误码
limit_req_status 429;
 
server {
    location /update_content {        
        proxy_pass http://192.168.211.1:18081;
    }
 
    location /read_content {
        # 使用限流配置
        limit_req zone=contentRateLimit;
        proxy_pass http://192.168.211.1:18081;
    }
}
  • binary_remote_addr:表示基于客户端IP做限流,使用二进制来表示IP地址;
  • zone:定义共享内存区来存储访问信息;
  • contentRateLimit:10m 表示一个大小为10M,名字为contentRateLimit的内存区域; 1M能存储8000个IP地址的访问信息(64位平台);
  • rate:用于设置最大访问速率,rate=10r/s 表示每秒最多处理10个请求。Nginx 实际上以毫秒为粒度来跟踪请求信息,因此 10r/s 实际上是限制:每100毫秒处理一个请求;
  • limit_req_zone:只定义速度限制的相关参数,一般用于http块中,使其可以在多个相关server中使用;
  • limit_req:启用定义的限速参数;
    当存储空间耗尽的时候,如果需要记录新的值,那么就会通过LRU算法移除旧的变量来腾出空间,如果这样腾出来的空间还是不足以接纳新的记录值,那么nginx就会返回状态码503。此外,为了防止内存耗尽,nginx每次创建一个新记录值的时候就会清理掉两个60秒内没被使用过的旧记录值。
    (2) 支持处理突发流量
    超过流量不会立即被拒绝,允许加入一个队列,只有队列满了之后的请求才会被拒绝。如果有时正常流量突然增大,超出的请求将被拒绝,无法处理突发流量,就可以结合 burst 参数使用来解决该问题。

3.2支持处理突发流量

超过流量不会立即被拒绝,允许加入一个队列,只有队列满了之后的请求才会被拒绝。如果有时正常流量突然增大,超出的请求将被拒绝,无法处理突发流量,就可以结合 burst 参数使用来解决该问题。

# 限流设置,这只是设置流量限制和共享内存区域的参数,但实际上并不限制请求速率。具体的限制需要定义具体的url
limit_req_zone $binary_remote_addr zone=contentRateLimit:10m rate=10r/s;
 
server {
    location /update_content {        
        proxy_pass http://192.168.211.1:18081;
    }
 
    location /read_content {
        # 使用限流配置
        limit_req zone=contentRateLimit burst=4 nodelay;
        proxy_pass http://192.168.211.1:18081;
    }
}
  • burst :表示在超过设定的处理速率后能额外处理的请求数。burst=4表示有4个请求到达,Nginx
    会处理第一个请求,剩余3个请求将放入队列,然后每隔100ms从队列中获取一个请求进行处理。若请求数大于4,将拒绝处理多余的请求,直接返回503。排队中的请求虽然每100ms会处理一个,但却需要等待
    较长的处理时间。所以burst 往往结合 nodelay 一起使用,以实现削峰填谷的效果;
  • nodelay :假设我们的流量是 2,1,4,0,2
    ,正常的请求会存在峰值和谷值,代表每秒的请求数。这样当流控为2r/s,burst=4
    nodelay时,在第3秒请求数为4时(峰值),仍然允许直接处理4个请求,但是后续的请求会被拦截,保证总流量不超过2r/s,因此,当第四秒请求数为0时,就起到了削峰填谷的作用。假设流量是2,1,4,4,4
    ,峰值持续的时间比较长,那么从第二个峰值开始,就会被真的流控,被拒绝或进行排队,这样即使被处理,也会延迟稍高!

3.3控制并发连接数

Nginx内置的limit_conn_zone和limit_conn指令,提供了通过限制ip连接数来控制流量的能力。

其中只有当服务器正在处理请求并且已经读取了整个请求头时,才会计算为有效连接。
对应Nginx模块:ngx_http_limit_conn_module
(1) 控制每个IP的连接数

limit_conn_zone $binary_remote_addr zone=perip:10m;
 
server {       
 
    location /brand {
        # 同一个地址只允许连接2次
        limit_conn perip 2;
        proxy_pass http://192.168.211.1:18081;
    }
     
}

limit_conn_zone $binary_remote_addr zone=perip:10m :表示根据用户的IP地址来进行限制,设置共享内存大小为10M。

limit_conn perip 2 :表示同一个地址只允许连接2次。

(2) 控制与服务器的连接总数

# 根据server_name来限制,存储内存大小10M
limit_conn_zone $server_name zone=perserver:10m;
 
server {
 
    listen 80;
    server_name xx.com;
      
    location / {
        # 限制与服务器的总连接数
        limit_conn perserver 100;
        root   html;
        index  index.html index.htm;
    }
}

limit_conn_zone $server_name zone=perserver:10m :表示根据用户访问的server_name来进行限制,设置共享内存大小为10M。

limit_conn perserver 100 :表示同一个server只允许连接100次。

3.4控制访问速率

设置http请求传输多少字节后开始限速。
对应Nginx模块:ngx_http_core_module

location /flv/ {
    limit_rate_after 500k;
    # 带宽限制,对单个连接限速
    limit_rate       50k;
}

limit_rate_after 500k :表示传输的前500k数据不限速,500k之后再进行限速。

limit_rate 50k :对单个连接限速为50k/s。如果一个客户端发起两个连接,就是50k * 2。

3.5黑白名单

配置固定IP为黑名单,访问时会返回403 Forbidden。
nginx 是按照自上而下的顺序进行匹配,匹配到一个就不往下继续了,如遇到 return 指令时 return 指令还是会生效。

server {
    listen 8080;
    server_name _;
 
    location / {
        allow 192.168.135.1;
        deny all;
        return 200 "$remote_addr 正常访问 3";
    }
}
# 屏蔽单个ip访问
deny IP;
# 允许单个ip访问
allow IP;
# 屏蔽所有ip访问
deny all;
# 允许所有ip访问
allow all;
# 屏蔽整个段即从123.0.0.1到123.255.255.254访问的命令
deny 123.0.0.0/8
# 屏蔽IP段即从123.45.0.1到123.45.255.254访问的命令
deny 124.45.0.0/16
# 屏蔽IP段即从123.45.6.1到123.45.6.254访问的命令
deny 123.45.6.0/24
 
# 也可以通过配置文件来配置
include blockip.conf;

动态黑白名单:也可以采用Lua+Redis实现,将黑名单存入到Redis缓存,每次执行请求时,通过lua脚本先获取用户IP,匹配IP是否属于黑名单,如果是,则不让请求,如果不是,则放行。

 /**
     * provide by zym
     * 0 error(s), 0 warning(s)
     */

你可能感兴趣的:(nginx,运维,服务器)