具有多个漏孔的漏桶原理(nginx+lua实现)
为了解决nginx自带限流模块漏桶的不完美,我们要实现的是有n个漏孔的漏桶:
一个漏孔是请求微服务+mysql,
1个漏孔是从nosql缓存中获得数据,
1个漏孔是从静态文件中获得数据,
大大增加漏桶的容量,
上面这样的漏桶, 不但出水量增加, 而且桶的容量也大大增加。 实现这样的漏桶, 我们采用下面这样的设计:

改造前:
左边是普通的nginx漏桶原理, 保证对微服务+mysql是平缓的,我们不能把桶的容量设得过大。超出桶容量的请求 将被拒绝。由于桶很小, 很多请求会被拒绝掉,用户体验非常不好。服务器抗并发能力也并不高。
改造后: 右边是nginx+lua实现的多级缓存降级,可以在多种降级方案(mysql,nosql,静态文件)中自由切换,配备多个出水 口,这样桶的容量和每秒出水量都增加了不少。
实现
到git下载自动降级的 lua-resty-limit-traffic 模块
git clone https://github.com/openresty/lua-resty-limit-traffic
自动降级代码:
-- 加载nginx—lua限流模块
local limit_req = require "resty.limit.req"
-- 这里设置rate=50个请求/每秒,漏桶桶容量设置为1000个请求
-- 因为模块中控制粒度为毫秒级别,所以可以做到毫秒级别的平滑处理
local lim, err = limit_req.new("my_limit_req_store", 50, 1000)
if not lim then
ngx.log(ngx.ERR, "failed to instantiate a resty.limit.req object: ", err)
return ngx.exit(501)
end
local key = ngx.var.binary_remote_addr
local delay, err = lim:incoming(key, true)
ngx.say("计算出来的延迟时间是:")
ngx.say(delay)
--if ( delay <0 or delay==nil ) then
--return ngx.exit(502)
--end
-- 1000以外的就溢出
if not delay then
if err == "rejected" then
return ngx.say("1000以外的就溢出")
-- return ngx.exit(502)
end
ngx.log(ngx.ERR, "failed to limit req: ", err)
return ngx.exit(502)
end
-- 50-100的等待从微服务+mysql获取实时数据;(100-50)/50 =1
if ( delay >0 and delay <=1 ) then
ngx.say("第50-第100个 等待0-1秒后 从mysql获取数据")
ngx.sleep(delay)
-- 100-400的直接从redis获取实时性略差的数据;(400-50)/50 =7
elseif ( delay >1 and delay <=7 ) then
local resp, err = redis_instance:get("redis_goods_list_advert")
ngx.say("第100-第400个 降级为从redis获取数据")
ngx.say(resp)
return
-- 400-1000的从静态文件获取实时性非常低的数据(1000-50)/50 =19
elseif ( delay >7) then
ngx.say("第400-第1000个 降级为从静态文件(死页面)获取数据")
ngx.header.content_type="application/x-javascript;charset=utf-8"
local file = "/etc/nginx/html/goods_list_advert.json"
local f = io.open(file, "rb")
local content = f:read("*all")
f:close()
ngx.print(content)
return
end
ngx.say("进入查询微服务+mysql(最实时的数据,进入这里就是没降级)")nginx配置
user nobody;
worker_processes 1;
events {
worker_connections 1024;
}
http {
#/usr/share/lua/5.1/lua-resty-limit-traffic-master/lib/?.lua;;
lua_package_path "/usr/share/lua/5.1/lua-resty-limit-traffic-master/lib/?.lua;;/usr/share/lua/5.1/lua-resty-redis/lib/?.lua;;/usr/share/lua/5.1/lua-resty-redis-cluster/lib/resty‘7/?.lua;;";
lua_package_cpath "/usr/share/lua/5.1/lua-resty-redis-cluster/lib/libredis_slot.so;;";
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
lua_shared_dict my_limit_req_store 100m;
server {
listen 80;
server_name 127.0.0.1;
server_name 192.168.232.200;
#获取广告推荐数据
location /goods_list_advert {
default_type 'application/x-javascript;charset=utf-8';
content_by_lua_file /etc/nginx/lua/goods_list_advert.lua;
}
#从服务层+mysql获取数据
location /goods_list_advert_from_data {
#allow 127.0.0.1;
#deny all;
default_type 'application/x-javascript;charset=utf-8';
#rewrite https//www.baidu.com/ break;
proxy_pass http://192.168.232.201:18306/goods/getList;
#content_by_lua '
# ngx.say("从服务层+mysql获取数据")
#';
}
}
}本文由:xiaoshu168.com 作者:xiaoshu发表,转载请注明来源!