PHP

首页 -  PHP  -  具有多个漏孔的漏桶原理(nginx+lua实现)

具有多个漏孔的漏桶原理(nginx+lua实现)

具有多个漏孔的漏桶原理(nginx+lua实现)

为了解决nginx自带限流模块漏桶的不完美,我们要实现的是有n个漏孔的漏桶:

一个漏孔是请求微服务+mysql,

1个漏孔是从nosql缓存中获得数据, 

1个漏孔是从静态文件中获得数据,

大大增加漏桶的容量, 

上面这样的漏桶, 不但出水量增加, 而且桶的容量也大大增加。 实现这样的漏桶, 我们采用下面这样的设计:

WPS图片编辑.png

改造前: 

左边是普通的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获取数据")
            #';
        }
    }
}


(0)
分享:

本文由:xiaoshu168.com 作者:xiaoshu发表,转载请注明来源!

相关阅读