1.5W 还是可以扛得住的。
这里请允许我设计一套方案(可能跟实际的需求有出入,只是提供一个思路而已):
基于 dict 的方案,有两个困难,一个是 url 对内存消耗大,另一个是不好统计最近 1 分钟的请求数。
前者比较好解决,可以采用 murmurhash 来 hash url。murmurhash 可以把字符串 hash 成一个 32 位整数,有现成的实现:
https://github.com/bungle/lua-resty-murmurhash2/blob/master/lib/resty/murmurhash2.lua
后一个比较棘手。要想统计最近 1 分钟的请求数,需要知道请求数和时间的对应关系。
我的思路比较奇葩,是维持每个 url+upstream 对应的总请求数和总流量,然后由一个 timer 每秒减去过期的请求和流量。
比如这样:
每次请求结束时,添加三个操作:
incr url+upstream+reqs 1
incr url+upstream+flow $flow
rpush tostring(math.floor(ngx_time)+60s) url+upstream+$flow
然后弄一个 timer,lpop tostring(math.floor(ngx_time)),获取 url+upstream+$flow,根据前面的 url+upstream 定位对应的请求数键和流量键,
减去过期的数据。清除减为 0 的 url+upstream+reqs 和 url+upstream+flow。一直 lpop 直到返回 nil 为止。
写了比较粗糙的代码测了下,timer 处理 10 万条这样的记录,用时不会超过一秒。这还是在我的老爷笔记本上的情况,如果是一般的服务器,用时会更短。
如果这样的效率不能忍受,可以开多个 timer 并行处理。
shdict 每个节点结构体,占用大小不到 64 字节(我记得是 40 个字节?)。反正算上其他辅助的存储结构,算它一个节点结构体 64 字节好了。算上节点的 key 和 value 数据,预估是 96 个字节。
假设每个节点占用 96 字节,则 shdict 总占用会是:
(url_num * upstream_num * 2 + qps * 60) * 96
设 url_num = 15000, upstream_num = 16, qps = 100000,得 593 M 字节。
当然这个方案可能还有漏洞,欢迎进一步讨论、吐槽~
------------------ 原始邮件 ------------------
发件人: "魏海通";<pu...@gmail.com>;
发送时间: 2017年6月18日(星期天) 下午5:28
收件人: "openresty"<openresty@googlegroups.com>;
主题: [openresty] Re: 热点均衡
多谢,峰值多则1.5W左右的链接
在 2017年6月16日星期五 UTC+8下午10:22:18,Zexuan Luo写道:
url 量级大概会到多少呢?
另外 access 日志能获取的数据,在 log_by_lua* 阶段也是能获取的。统计加反馈可以试下单独开个 timer 来做。
在 2017年6月16日星期五 UTC+8下午3:38:39,魏海通写道:
nginx version: openresty/
1.11.2.1每个OR实例代理(proxy_pass upstream)到4台服务端。
hash $http_host$request_uri consistent;
>
需求是检测最近一分钟的 URL的QPS 和 每个服务器端的流量。如果有某个QPS 超大或者流量大,需要热点均衡到更多的设备上面。
>
开始考虑是dict上面用URL的md5值做key,这样如果url很多消耗内存且不好统计最近1分钟的请求数。
然后如果借助缓存redis来做,每个请求都过一下redis,性能势必消耗。
最后妥协的做法是其他进程来读取access日志实时统计再反馈给OR做调整。
请问大家有更好的方法来做不?
--