Nginx 限流可以通过几种方式实现:
ngx_http_limit_req 根据特定的key(通常为IP) 控制访问频率
ngx_http_limit_req_module 控制连接数
通过修改Nginx的配置文件,然后reload。这种方式配置比较简单,然而 reload 对于当前访问量比较大的服务器开销也有一些。 根据新浪的经验,每一次的 reload 对 Nginx 的 QPS 与耗时的影响通常会持续 8~10s,考虑到一次扩容会有频繁的变更,这对在线业务来说是不堪承受之重。因此,要避免对 Nginx 进行 reload。
代码和文档。这个库分为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。 通俗的理解就是顾客进入试衣间前持一个牌子,出来后归还牌子。当前的正在使用的牌子数目可以配置,以达到限流目的。
依据系统状态动态改变限流的配置,可以考虑两种方案:
a. limit_conn 和 limit_delay 存放在 Redis内,在 access_by_lua_block 的部分去取出当前限制,这个方案的弊端在于对每个 request 多了一次 redis 请求。
b. limit_conn存放在 Nginx 的 shared_dict内,通过 Nginx 的配置增加一个 location,专门用来请求来修改其值,任何一个 Nginx worker 修改成功后,其他 worker 都可见。
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日志。