在开发高并发系统时有三把利器用来保护系统:缓存、降级和限流。

缓存

缓存比较好理解,在大型高并发系统中,如果没有缓存数据库将分分钟被爆,系统也会瞬间瘫痪。使用缓存不单单能够提升系统访问速度、提高并发访问量,也是保护数据库、保护系统的有效方式

降级

服务降级是当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源保证核心任务的正常运行。降级往往会指定不同的级别,面临不同的异常等级执行不同的处理。根据服务方式:可以拒接服务,可以延迟服务,也有时候可以随机服务。根据服务范围:可以砍掉某个功能,也可以砍掉某些模块。总之服务降级需要根据不同的业务需求采用不同的降级策略。主要的目的就是服务虽然有损但是总比没有好

限流

限流可以认为服务降级的一种,限流就是限制系统的输入和输出流量已达到保护系统的目的。一般来说系统的吞吐量是可以被测算的,为了保证系统的稳定运行,一旦达到的需要限制的阈值,就需要限制流量并采取一些措施以完成限制流量的目的。比如:延迟处理,拒绝处理,或者部分拒绝处理等等。。一般地说,限流是用在保护上游应用服务器不被在同一时刻的大量用户请求湮没。可以帮助防范DDos攻击

nginx层的限流

对于Nginx接入层限流可以使用Nginx自带了两个模块:

  • ngx_http_limit_conn_module 用来限制同一时间连接数,即并发限制。
  • ngx_http_limit_req_module 用来限制单位时间内的请求数,即速率限制,采用的漏桶算法 "leaky bucket"。[Nginx version≥1.7.6]

1、 ngx_http_limit_req_module

1.1 limit_req_zone

配置段:

http

使用语法:

limit_req_zone [key] zone=[name]:[size] rate=[rate]; 

例子:

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

第一个参数:$binary_remote_addr 表示通过remote_addr这个标识来做限制,“binary_”的目的是缩写内存占用量,是限制同一客户端ip地址。
第二个参数:zone=one:10m表示生成一个大小为10M,名字为one的内存区域,用来存储访问的频次信息。
第三个参数:rate=1r/s表示允许相同标识的客户端的访问频次,这里限制的是每秒1次,还可以有比如30r/m的。
1.2 limit_req

配置段:

http,server,location 

使用语法:

limit_req zone=[name] [burst=number] [nodelay]; 

例子:

limit_req zone=one burst=5 nodelay;

第一个参数:zone=one 设置使用哪个配置区域来做限制,与上面limit_req_zone 里的name对应。
第二个参数:burst=5,重点说明一下这个配置,burst爆发的意思,这个配置的意思是设置一个大小为5个请求的缓冲区,当有大量请求(爆发)过来时,超过了访问频次限制的请求可以先放到这个缓冲区内。
第三个参数:nodelay,如果设置,超过访问频次而且缓冲区也满了的时候就会直接返回503,如果没有设置,则所有请求会等待排队。
1.3 limit_req_log_level

当服务器由于limit被限速或缓存时,配置写入日志的级别

配置段:

http, server, location

使用语法:

#默认error
limit_req_log_level info | notice | warn | error;
1.4 limit_req_status

设置拒绝请求的返回值。值只能设置 400 到 599 之间。

配置段:

http, server, location

使用语法:

#默认error
limit_req_log_level info | notice | warn | error;
1.5 完整例子
#例子1
http {
    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
    server {
        location /search/ {
            limit_req zone=one burst=5 nodelay;
        }
}  

#例子2
http {
    # 根据客户端IP地址进行统计,设置共享内存大小为20MB,设置固定速率大小为10r/s 
    limit_req_zone $binary_remote_addr zone=addr:20m rate=10r/s; 
    # 设置并发限流的日志级别为error 
    limit_req_log_level  error; 
    # 设置触发并发限制时直接返回503状态码 
    limit_req_status 503;

    server{ 
        # ... 
        location /limit{ 
            # 设置每个IP的桶容量为10 
            # nodelay表示超额则立即返回503错误 
            # 没有配置nodelay表示超过后请求就会排队等待 
            limit_req zone=addr burst=10 nodelay; 

        } 
    } 
} 

2、 ngx_http_limit_conn_module

这个模块用来限制单个IP的请求数。并非所有的连接都被计数。只有在服务器处理了请求并且已经读取了整个请求头时,连接才被计数。

2.1 limit_conn && limit_conn_zone

limit_conn_zone配置段:

http

limit_conn_zone使用语法:

limit_conn_zone key zone=name:size;

limit_conn配置段:

http, server, location

limit_conn使用语法:

limit_conn zone number;

例子:

#例子1
http{
    limit_conn_zone $binary_remote_addr zone=addr:10m;
    server {
        location /download/ {
            limit_conn addr 1;# 一次只允许每个IP地址一个连接。
        }
    }
}

#例子2
/*
可以配置多个limit_conn指令。
例如,下面配置将限制每个客户端IP连接到服务器的数量,
同时限制连接到虚拟服务器的总数
*/
http{
    limit_conn_zone $binary_remote_addr zone=perip:10m;
    limit_conn_zone $server_name zone=perserver:10m;
    server {
        ...
        limit_conn perip 10;
        limit_conn perserver 100;
    }
}
2.2 limit_conn_log_level

limit_conn_log_level 主要用于配置被限流后的日志级别,默认为error级别。该功能只有Nginx version≥0.8.18的版本才被支持。

配置段:

http,server,location 

使用语法:

limit_conn_log_level info|notice|warn|error; 

# 默认
limit_conn_log_level error; 
2.3 limit_conn_status

limit_conn_status 主要用于配置被限流后的返回的状态,默认会返回503状态码。该功能只有Nginx version≥1.3.15的版本才被支持。

配置段:

http, server, location

使用语法:

limit_conn_status 503; 

/*
凡事都具有两面性,ngx_http_limit_req_module
模块虽可以解决当前面临的并发问题,但也会引入另外一些问题。
如前端如果有做LVS或反向代理,而后端启用了该模块功能,
那该机器的IP访问会特别频繁,从而导致经常出现503错误,
但可以通过设置IP白名单来进行过滤解决该问题,简单配置方式如:
*/

location / { 
    # 允许一个IP的访问 
    allow 10.1.1.16; 
} 

参考:

1、https://www.jianshu.com/p/2cf3d9609af3