Nginx 限流可以通过几种方式实现:
1. Nginx 自带的流量控制模块
ngx_http_limit_req 根据特定的 key(通常为 IP) 控制访问频率
ngx_http_limit_req_module 控制连接数
通过修改 Nginx 的配置文件,然后 reload。这种方式配置比较简单,然而 reload 对于当前访问量比较大的服务器开销也有一些。
根据新浪的经验,每一次的 reload 对 Nginx 的 QPS 与耗时的影响通常会持续 8~10s,考虑到一次扩容会有频繁的变更,这对在线业务来说是不堪承受之重。因此,要避免对 Nginx 进行 reload。
2. 使用 lua-resty-limit-traffic 流量控制
代码和文档。这个库分为 limit_conn 和 limit_req 模块,limit_req 限制某个 ip 或者 server 的访问频率,limit_conn 限制连接数。lua-resty-limit-traffic 的原理是使用 Nginx 的 shared_dict,建立一个 hashtable,根据目前连接数或者访问请求记录相关信息。对于每一个 Nginx 请求都有 一系列执行阶段,每个阶段可以增加 hook,access_by_lua 是处理前调用的 hook, log_by_lua 是处理完成后调用的 hook。进入的时候通过 ip 作为 key 找到 share_dict 里面的连接数,增加 1。处理完之后找到连接数,减去 1。通俗的理解就是顾客进入试衣间前持一个牌子,出来后归还牌子。当前的正在使用的牌子数目可以配置,以达到限流目的。
依据系统状态动态改变限流的配置,可以考虑两种方案:
limit_conn 和 limit_delay 存放在 Redis 内,在 access_by_lua_block 的部分去取出当前限制,这个方案的弊端在于对每个 request 多了一次 redis 请求。
limit_conn 存放在 Nginx 的 shared_dict 内,通过 Nginx 的配置增加一个 location,专门用来请求来修改其值,任何一个 Nginx worker 修改成功后,其他 worker 都可见。
3. 使用 nginx-upsync-module
nginx-upsync-module是新浪的开源库,也是依赖 openresty 的。这套工具可以修改 backend 的各种属性,weight, max_fails 等。为了避免 reload,可以使用 Consul 或者 Etcd 进行动态配置。
其他
为了做一些自动限流,可以考虑分析 nginx 日志,或者系统负载信息。
系统负载分析工具,ruby gem 包 usagewatch 可以获取系统目前的 CPU 使用率,Memory 使用率,系统 load 等相关信息,
日志分析工具 https://github.com/allinurl/goaccess,使用 goaccess,可以实时分析 rails app 日志。