运维框架建设收集python

Nginx 限流 [7]

2019-07-23  本文已影响246人  大鱼炖海棠

系统设计时一般会预估负载,当系统遭受恶意攻击或正常突发流量等都可能导致系统被压垮,而限流就是保护措施之一。

一、限流算法介绍

令牌桶算法

令牌桶限流

算法思想是:

漏桶算法

漏桶算法

算法思想是:

这个算法的核心是:缓存请求、匀速处理、多余的请求直接丢弃。

漏桶和令牌桶算法最明显的区别在于是否允许突发流量(burst)的处理,漏桶算法能够强行限制数据的实时传输(处理)速率,对突发流量不做额外处理;而令牌桶算法能够在限制数据的平均传输速率的同时允许某种程度的突发传输。

二、Nginx 限流

Nginx 提供两种限流方式,一是控制速率,二是控制并发连接数:

控制速率

ngx_http_limit_req_module 模块提供限制请求处理速率能力,它能够有效针对同一个 IP 反复请求服务器,如洪水攻击或者 DDos 攻击。下面例子使用 nginx 的 limit_req_zone 和 limit_req 两个指令,限制单个IP的请求处理速率。

在 nginx.conf 的 http 域中添加限流配置:

# 格式:limit_req_zone key zone rate
http {
    limit_req_zone $binary_remote_addr zone=myRateLimit:10m rate=10r/s;
}

# 配置 server,使用 limit_req 指令应用限流。
server {
    location / {
        limit_req zone=myRateLimit;
        proxy_pass http://my_upstream;
    }
}

处理突发流量

上面例子限制 10r/s,正常流量稍微增大,请求就会被拒绝,面对突发流量,可以结合 burst 参数使用来解决该问题。

server {
    location / {
        limit_req zone=myRateLimit burst=20;
        proxy_pass http://my_upstream;
    }
}

burst 译为突发、爆发,表示在超过设定的处理速率后能额外处理的请求数。当 rate=10r/s 时,将1s拆成10份,即每100ms可处理1个请求。此处,burst=20,若同时有20个请求到达,Nginx 会处理第一个请求,剩余19个请求将放入队列,然后每隔100ms从队列中获取一个请求进行处理。若请求数大于20,将拒绝处理多余的请求,直接返回 503

不过,单独使用 burst 参数并不实用。假设 burst=50,rate依然为10r/s,排队中的50个请求虽然每100ms会处理一个,但第50个请求却需要等待 50 * 100ms即 5s,这么长的处理时间自然难以接受。因此,burst 往往结合 nodelay 一起使用。

server {
    location / {
        limit_req zone=myRateLimit burst=20 nodelay;
        proxy_pass http://my_upstream;
    }
}

nodelay 针对的是 burst 参数,burst=20 nodelay 表示这20个请求立马处理,不能延迟,相当于特事特办。不过,即使这20个突发请求立马处理结束,后续来了请求也不会立马处理。burst=20 相当于缓存队列中占了20个坑,即使请求被处理了,这20个位置这只能按 100ms 一个来释放。
这就达到了速率稳定,但突然流量也能正常处理的效果。

限制连接数

ngx_http_limit_conn_module 提供了限制连接数的能力,利用 limit_conn_zone 和 limit_conn 两个指令即可。下面是 Nginx 官方例子:

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;
}

需要注意的是:只有当 request header 被后端 server 处理后,这个连接才进行计数。

设置白名单

限流主要针对外部访问,内网访问相对安全,可以不做限流,通过设置白名单即可。利用 Nginx ngx_http_geo_module 和 ngx_http_map_module 两个工具模块即可搞定。

在 nginx.conf 的 http 部分中配置白名单:

geo $limit {
    default 1;       // key=default,  value=1  
    10.0.0.0/8 0;
    192.168.0.0/24 0;
    172.20.0.35 0;
    include conf/whiteip.conf;  // 支持白名单以 key:value的形式存储在配置文件中
}

map $limit $limit_key {
    0 "";
    1 $binary_remote_addr; // value=1则返回 $binary_remote_addr,也就是IP,否则返回空字符串  
}

limit_req_zone $limit_key zone=myRateLimit:10m rate=10r/s;
上一篇 下一篇

猜你喜欢

热点阅读