灰度配置

 

1、openresty配置

2、参照nginx_2B.conf

#user  appdeploy;
worker_processes  2;

error_log  logs/2B_error.log;
#error_log  logs/2B_error.log  notice;
#error_log  logs/2B_error.log  info;

pid        logs/nginx_2B.pid;

events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent $request_time "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" '
                      '$upstream_addr $upstream_status $upstream_response_time';

    access_log  logs/2B_access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    tcp_nopush      on;
    tcp_nodelay     on;

    gzip on;
    gzip_min_length    1k;
    gzip_buffers       4 16k;
    gzip_http_version  1.0;
    gzip_comp_level    2;
    gzip_types         text/plain application/x-javascript text/css application/xml application/json;
    gzip_vary          on;
    gzip_proxied       any;
    client_max_body_size 5M;

    #lua_package_path "/usr/local/fezs_bas_gray/?.lua;/usr/local/fezs_boms_gray/?.lua;/usr/local/openresty/fezs_mall_gray?.lua;/usr/local/fezs_b_gray/?.lua;/usr/local/openresty/lualib/?.lua;;";
    lua_package_path "/usr/local/openresty/fezs_mgroup_gray/?.lua;/usr/local/fezs_bas_gray/?.lua;/usr/local/fezs_boms_gray/?.lua;/usr/local/openresty/fezs_mall_gray?.lua;/usr/local/fezs_b_gray/?.lua;/usr/local/openresty/ratelimiter-shopapi/?.lua;/usr/local/openresty/lualib/?.lua;;";
    lua_package_cpath "/usr/local/openresty/lualib/?.so;;";

    lua_shared_dict runtime 10m;
    lua_shared_dict limitcache 100m;
    lua_shared_dict blacklistcache 10m;
    lua_shared_dict limitconfigcache 5m;

    # Upstream Conf
    upstream static_web_bas{
       ip_hash;
       server 10.200.130.43:8088 ;
       server 10.200.130.35:8088 ;
    }
    upstream static_web_boms{
       ip_hash;
       server 10.200.130.43:8089 ;
       server 10.200.130.35:8089 ;
    }
    upstream static_web_bssp{
       ip_hash;
       server 10.200.130.43:8090 ;
       server 10.200.130.35:8090 ;
    }
    upstream static_web_mall{
       ip_hash;
       server 10.200.130.43:8091 ;
       server 10.200.130.35:8091 ;
       #server 10.200.130.43:8191 ;
    }
    upstream static_web_bmall{
       ip_hash;
       server 10.200.130.43:8092 ;
       server 10.200.130.35:8092 ;
    }
    upstream static_web_scm{
       ip_hash;
       server 10.200.130.43:8093 ;
    }

    upstream static_web_bas_gray{
       server 10.200.130.43:8188 ;
    }
    upstream static_web_boms_gray{
       server 10.200.130.43:8189 ;
    }
    upstream static_web_bssp_gray{
       server 10.200.130.43:8190 ;
    }
    upstream static_web_mall_gray{
       server 10.200.130.43:8191 ;
    }
    upstream static_web_bmall_gray{
       server 10.200.130.43:8192 ;
    }
    upstream static_web_scm_gray{
       server 10.200.130.43:8193 ;
    }

    upstream bas_api{
       server 10.200.130.14:8038 ;
       server 10.200.130.3:8038 ;
    }
    upstream boms_api{
       server 10.200.130.14:8048 ;
       server 10.200.130.3:8048 ;
    }   
    upstream bssp_api{
       server 10.200.130.14:8058 ;
       server 10.200.130.3:8058 ;
    }   
    upstream mall_api{
       server 10.200.130.7:8078 ;
       server 10.200.130.12:8078 ;
    }   
    upstream bmall_api{
       server 10.200.130.26:8098 ;
       server 10.200.130.27:8098 ;
    }   
    upstream scm_api{
       server 10.200.130.39:8108 ;
       server 10.200.130.113:8108 ;
    }   

    upstream bmall_api_gray{
       server 10.200.130.90:8098 ;
    }   
    upstream bas_api_gray{
       server 10.200.130.90:9038 ;
    }
    upstream boms_api_gray{
       server 10.200.130.90:9048 ;
    }   
    upstream bssp_api_gray{
       server 10.200.130.90:9058 ;
    }   
    upstream mall_api_gray{
       server 10.200.130.126:9078 ;
    }

    # wxadmin_api
    upstream wxadmin_api_1{
       server 10.200.130.3:8018 ;
       server 10.200.130.14:8018 ;
    }

    upstream wxadmin_api_gray{
       server 10.200.130.31:8018 ;
    }

    # wxapp_api
    upstream wxapp{
       server 10.200.130.7:8008 weight=5;
       server 10.200.130.12:8008 weight=5;
       #server 10.200.130.73:8008 weight=5;
       #server 10.200.130.8:8008 weight=5;
    }
    upstream wxapp_gray{
       #server 10.200.130.8:8008 weight=5;
       server 10.200.130.136:8008 weight=5;
    }

    # Server Conf
    server {
        listen       8028;
        server_name  bas.feng1.com;

        set $redis_host '10.200.130.138';
        set $redis_port '6379';
        set $redis_password 'DK11rrMN';
        set $redis_connect_timeout 0;
        set $redis_dbid 0;
        set $redis_pool_size 100;
        set $redis_keepalive_timeout 5000;

        location /api {
                set $runtime      'runtime';
                set $backend 'bas_api';
                rewrite  ^/api/(.*)$ /$1 break;
                rewrite_by_lua_file /usr/local/fezs_bas_gray/bas-api.lua;
                #proxy_pass http://bas_api;
                proxy_pass http://$backend;
                proxy_redirect off;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header REMOTE-HOST $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    
        location / {
                set $runtime      'runtime';
                set $backend 'static_web_bas';
                rewrite_by_lua_file /usr/local/fezs_bas_gray/bas-web.lua;
                #proxy_pass http://static_web_bas;
                proxy_pass http://$backend;
                proxy_redirect off;
                #proxy_redirect http://bas.feng1.com:8088(.*) https://bas.feng1.com$1;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header REMOTE-HOST $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

        location /wxadmin {
            set $runtime      'runtime';
            set $backend 'wxadmin_api_1';
            rewrite  ^/wxadmin/(.*)$ /$1 break;
            rewrite_by_lua_file /usr/local/fezs_bas_gray/bas-adminapi.lua;
            proxy_pass http://$backend;
            #proxy_redirect default;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header REMOTE-HOST $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }

    server {
        listen       8029;
        server_name  boms.feng1.com bssp.feng1.com mall.feng1.com bmall.feng1.com scm.feng1.com;
        rewrite ^(.*)$  https://$host$1 permanent;
    }

    server {
        listen       8028;
        server_name  boms.feng1.com;

        set $redis_host '10.200.130.138';
        set $redis_port '6379';
        set $redis_password 'DK11rrMN';
        set $redis_connect_timeout 0;
        set $redis_dbid 0;
        set $redis_pool_size 100;
        set $redis_keepalive_timeout 5000;

        location /api {
                set $runtime      'runtime';
                set $backend 'boms_api';
                rewrite  ^/api/(.*)$ /$1 break;
                rewrite_by_lua_file /usr/local/fezs_boms_gray/boms-api.lua;
                #proxy_pass http://boms_api;
                proxy_pass http://$backend;
                proxy_redirect off;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header REMOTE-HOST $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
       
        location / {
                set $runtime      'runtime';
                set $backend 'static_web_boms';
                rewrite_by_lua_file /usr/local/fezs_boms_gray/boms-web.lua;
                #proxy_pass http://static_web_boms;
                proxy_pass http://$backend;
                proxy_redirect off;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header REMOTE-HOST $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
        
        location /wxadmin {
            rewrite  ^/wxadmin/(.*)$ /$1 break;
            proxy_pass http://wxadmin_api_1;
            #proxy_redirect default;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header REMOTE-HOST $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }


    server {
        listen       8028;
        server_name  bssp.feng1.com;

        set $redis_host '10.200.130.138';
        set $redis_port '6379';
        set $redis_password 'DK11rrMN';
        set $redis_connect_timeout 0;
        set $redis_dbid 0;
        set $redis_pool_size 100;
        set $redis_keepalive_timeout 5000;

        location /api {
                set $runtime      'runtime';
                set $backend      'bssp_api';
                rewrite  ^/api/(.*)$ /$1 break;
                rewrite_by_lua_file /usr/local/fezs_b_gray/b-api.lua;
                #proxy_pass http://bssp_api;
                proxy_pass http://$backend;
                proxy_redirect off;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header REMOTE-HOST $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
       
        location / {
                set $runtime      'runtime';
                set $backend      'static_web_bssp';
                rewrite_by_lua_file /usr/local/fezs_b_gray/b-web.lua;
                #proxy_pass http://static_web_bssp;
                proxy_pass http://$backend;
                proxy_redirect off;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header REMOTE-HOST $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
        
    }

    server {
        listen       8028;
        server_name  mall.feng1.com;
        access_log  logs/mall.feng1.com.log  main;
               #redis gray
                set $redis_host '10.200.130.138';
                set $redis_port '6379';
                set $redis_password 'DK11rrMN';
                set $redis_connect_timeout 0;
                set $redis_dbid 0;
                set $redis_pool_size 100;
                set $redis_keepalive_timeout 5000;

        location /api {
                set $runtime      'runtime';
                set $backend 'mall_api';
                set $limitcache      'limitcache';
                set $blacklistcache      'blacklistcache';
                set $limitconfigcache      'limitconfigcache';
                rewrite_by_lua_file /usr/local/openresty/fezs_mall_gray/mall-api.lua;
                rewrite  ^/api/(.*)$ /$1 break;
                access_by_lua_file /usr/local/openresty/ratelimiter-shopapi/ratelimiter-dict.lua;
                proxy_pass http://$backend;
                proxy_redirect off;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header REMOTE-HOST $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
       
        location /wxapp {
            set $runtime      'runtime';
            set $backend 'wxapp';
            rewrite  ^/wxapp/(.*)$ /$1 break;
            rewrite_by_lua_file /usr/local/openresty/fezs_mall_gray/mall-wxapp-api.lua;
            #proxy_pass http://wxapp_gray;
            proxy_pass http://$backend;
           #proxy_redirect default;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header REMOTE-HOST $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

        location / {
                set $runtime      'runtime';
                set $backend 'static_web_mall';
                rewrite_by_lua_file /usr/local/openresty/fezs_mall_gray/mall-web.lua;
                proxy_pass http://$backend;
                proxy_redirect off;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header REMOTE-HOST $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
        
       # location / {
       #             echo "system maintenance" ;
       # }
    }

    server {
        listen       8028;
        server_name  bmall.feng1.com;
        access_log  logs/bmall.feng1.com.log  main;
        set $redis_host '10.200.130.138';
        set $redis_port '6379';
        set $redis_password 'DK11rrMN';
        set $redis_connect_timeout 0;
        set $redis_dbid 0;
        set $redis_pool_size 100;
        set $redis_keepalive_timeout 5000;

        location /mapi {
                set $runtime 'runtime';
                set $backend 'bmall_api';
                rewrite  ^/mapi/(.*)$ /$1 break;
                rewrite_by_lua_file /usr/local/openresty/fezs_mgroup_gray/mgroup-api.lua;
                proxy_pass http://$backend;
            #   proxy_pass http://bmall_api;
                proxy_redirect off;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header REMOTE-HOST $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
       
        location /wxapp {
                set $runtime 'runtime';
                set $backend 'wxapp';
                rewrite  ^/wxapp/(.*)$ /$1 break;
                rewrite_by_lua_file /usr/local/openresty/fezs_mgroup_gray/mgroup-wxapp-api.lua;
                proxy_pass http://$backend;
                #proxy_pass http://wxapp_gray;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header REMOTE-HOST $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

        location / {
                set $runtime      'runtime';
                set $backend 'static_web_bmall';
                rewrite_by_lua_file /usr/local/openresty/fezs_mgroup_gray/mgroup-web.lua;
                proxy_pass http://$backend;
              #  proxy_pass http://static_web_bmall;
                proxy_redirect off;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header REMOTE-HOST $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }

    server {
        listen       8028;
        server_name  scm.feng1.com;
        access_log  logs/scm.feng1.com.log  main;
        
        location /api {
                rewrite  ^/api/(.*)$ /$1 break;
                proxy_pass http://scm_api;
                proxy_redirect off;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header REMOTE-HOST $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
       

        location / {
                proxy_pass http://static_web_scm;
                proxy_redirect off;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header REMOTE-HOST $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }

}

 

3、企业购灰度例子

lua文件路径

server配置

 

upstream

api

wxapp

 

web_bmall

 

4、redis配置

企业购灰度环境

Redis灰度操作
// 打开灰度开关
hset gray:mgroup switch on
// 关闭灰度开关
hset gray:mgroup switch off
// 查看灰度开关
hgetall gray:mgroup


// 添加灰度用户
sadd gray:mgroup:userid (用户ID)
// 删除灰度用户
srem gray:mgroup:userid (用户ID)
// 查看所有灰度用户
smembers gray:mgroup:userid

// 添加灰度ip
sadd gray:mgroup:ip (ip)
// 删除灰度ip
srem gray:mgroup:ip (ip)
// 查看所有灰度ip
smembers gray:mgroup:ip

// 添加api灰度upstream
hset gray:mgroup:upstream api (对应upstream)
// 删除api灰度upstream
hdel gray:mgroup:upstream api

// 添加api灰度upstream
hset gray:mgroup:upstream wxappapi(对应upstream)
// 删除api灰度upstream
hdel gray:mgroup:upstream wxappapi

// 配置web灰度upstream
hset gray:mgroup:upstream web (对应upstream)
// 删除web灰度upstream
hdel gray:mgroup:upstream web

// 查看灰度upstream
hgetall gray:mgroup:upstream

 

5、lua文件

mgroup-api.lua

local redisModile = require('utils.redis')
local systemConf = require('utils.init')
local cache = require('utils.cache')
local ipParser = require('utils.ipParser')
local redisConf = systemConf.redisConf
local upstream = nil

local red = redisModile:new(redisConf)

local gray_type = "gray:mgroup:"

local redis_config_key = gray_type.."config"
local redis_userid_key = gray_type.."userid"
local redis_ip_key = gray_type.."ip"
local redis_upstream_key = gray_type.."upstream"

local dict_refresh_key = gray_type.."refresh"
local dict_switch_key = gray_type.."switch"
local dict_userid_api_key = gray_type.."userid:api"
local dict_userid_wxappapi_key = gray_type.."userid:wxappapi"
local dict_userid_web_key = gray_type.."userid:web"
local dict_ip_api_key = gray_type.."ip:api"
local dict_ip_wxappapi_key = gray_type.."ip:wxappapi"
local dict_ip_web_key = gray_type.."ip:web"


-- get all cookies
function get_cookies()
  local cookies = ngx.header["Set-Cookie"] or {}
  if type(cookies) == "string" then
    cookies = {cookies}
  end
  return cookies
end

-- add cookie
function add_cookie(cookie)
  local cookies = get_cookies()
  table.insert(cookies, cookie)
  ngx.header['Set-Cookie'] = cookies
end

-- get userId
function get_userid()
        local userId = nil
    userId = ngx.req.get_headers()["Feng1-UserId"]
        
        if userId then
        ngx.log(ngx.INFO, "head : userId = "..userId)
                add_cookie("userId="..userId.."; Path=/; Expires="..ngx.cookie_time(ngx.time() + 180))
        else
                userId = ngx.var.cookie_userId
                if not userId then
                        ngx.log(ngx.INFO, "userId is nil")
                else
                        ngx.log(ngx.INFO, "cookies : userId = "..userId)
                end
        end
        
        return userId
end

-- connect redis
local connectdb = function(red, redisConf)
    if not red then
        red = redisModile:new(redisConf)
    end
    local ok, err = red:connectdb()
    if not ok then
        ngx.log(ngx.ERR, "Redis connect error!")
        return false, err
    end

    return ok, red
end

-- set redis pool
local setKeepalive = function(red) 
    local ok, err = red:keepalivedb()  
    if not ok then
        ngx.log(ngx.ERR, "Redis keepalive error!")
        return
    end
end

-- check nginx cache,refresh 1 min
local checkfunc = function()
        local runtimeCache = cache:new(ngx.var.runtime)
        local refreshFlag = runtimeCache:getRefreshFlag(dict_refresh_key)
        
        if refreshFlag then
                ngx.log(ngx.INFO, 'cache refreshFlag:'..refreshFlag)
                return true,'ok'
        else
                ngx.log(ngx.INFO, 'refresh cache......')
        end
        
    local ok, db = connectdb(red, redisConf)  
    local database = db.redis   
        
        runtimeCache:setRefreshFlag(dict_refresh_key)
        
        local switch = database:hget(gray_type,"switch");
        runtimeCache:setSwitch(dict_switch_key,switch)
        
        local apiUpstream = database:hget(redis_upstream_key,"api");
        local webUpstream = database:hget(redis_upstream_key,"web");
        local wxappapiUpstream = database:hget(redis_upstream_key,"wxappapi");
        
        local useridValues = database:smembers(redis_userid_key)
        for key, value in pairs(useridValues) do   
                runtimeCache:setUpstream(dict_userid_api_key..value,apiUpstream)
                runtimeCache:setUpstream(dict_userid_web_key..value,webUpstream)
                runtimeCache:setUpstream(dict_userid_wxappapi_key..value,wxappapiUpstream)
        end     
        
        local ipValues = database:smembers(redis_ip_key)
        for key, value in pairs(ipValues) do   
                runtimeCache:setUpstream(dict_ip_api_key..value,apiUpstream)
                runtimeCache:setUpstream(dict_ip_web_key..value,webUpstream)
                runtimeCache:setUpstream(dict_ip_wxappapi_key..value,wxappapiUpstream)
        end     
        
    if red then setKeepalive(red) end           
end

local ok,err = pcall(checkfunc)

-- gray policy
local policyfunc = function()
        local ups = nil
        local runtimeCache = cache:new(ngx.var.runtime)
        
        local switch = runtimeCache:getSwitch(dict_switch_key)
        if "off" == switch then
                return true,nil
        end
        
        -- use userid policy
        local userid = get_userid()
        if userid then 
                ups = runtimeCache:getUpstream(dict_userid_api_key..userid)
        end
        if ups then
                upstream = ups
                return true,ups
        end     
        
        -- use ip policy
        local ip = ipParser.get()       
        ups = runtimeCache:getUpstream(dict_ip_api_key..ip)
        if ups then
                upstream = ups
                return true,ups
        end
        
        return true,nil
end

local ok,ups = pcall(policyfunc)

if upstream then
        ngx.log(ngx.INFO, 'backend = '..upstream)
    ngx.var.backend = upstream
end

 

mgroup-web.lua

local redisModile = require('utils.redis')
local systemConf = require('utils.init')
local cache = require('utils.cache')
local ipParser = require('utils.ipParser')
local redisConf = systemConf.redisConf
local upstream = nil

local red = redisModile:new(redisConf)

local gray_type = "gray:mgroup:"

local redis_config_key = gray_type.."config"
local redis_userid_key = gray_type.."userid"
local redis_ip_key = gray_type.."ip"
local redis_upstream_key = gray_type.."upstream"

local dict_refresh_key = gray_type.."refresh"
local dict_switch_key = gray_type.."switch"
local dict_userid_api_key = gray_type.."userid:api"
local dict_userid_wxappapi_key = gray_type.."userid:wxappapi"
local dict_userid_web_key = gray_type.."userid:web"
local dict_ip_api_key = gray_type.."ip:api"
local dict_ip_wxappapi_key = gray_type.."ip:wxappapi"
local dict_ip_web_key = gray_type.."ip:web"


-- get all cookies
function get_cookies()
  local cookies = ngx.header["Set-Cookie"] or {}
  if type(cookies) == "string" then
    cookies = {cookies}
  end
  return cookies
end

-- add cookie
function add_cookie(cookie)
  local cookies = get_cookies()
  table.insert(cookies, cookie)
  ngx.header['Set-Cookie'] = cookies
end

-- get userId
...skipping...
        
    if red then setKeepalive(red) end           
end

local ok,err = pcall(checkfunc)

-- gray policy
local policyfunc = function()
        local ups = nil
        local runtimeCache = cache:new(ngx.var.runtime)
        
        local switch = runtimeCache:getSwitch(dict_switch_key)
        if "off" == switch then
                return true,nil
        end
        
        -- use userid policy
        local userid = get_userid()
        if userid then 
                ups = runtimeCache:getUpstream(dict_userid_web_key..userid)
        end
        if ups then
                upstream = ups
                return true,ups
        end     
        
        -- use ip policy
        local ip = ipParser.get()       
        ups = runtimeCache:getUpstream(dict_ip_web_key..ip)
        if ups then
                upstream = ups
                return true,ups
        end
        
        return true,nil
end

local ok,ups = pcall(policyfunc)

if upstream then
        ngx.log(ngx.INFO, 'backend = '..upstream)
    ngx.var.backend = upstream
end

  

mgroup-wxapp-api.lua

local redisModile = require('utils.redis')
local systemConf = require('utils.init')
local cache = require('utils.cache')
local ipParser = require('utils.ipParser')
local redisConf = systemConf.redisConf
local upstream = nil

local red = redisModile:new(redisConf)

local gray_type = "gray:mgroup:"

local redis_config_key = gray_type.."config"
local redis_userid_key = gray_type.."userid"
local redis_ip_key = gray_type.."ip"
local redis_upstream_key = gray_type.."upstream"

local dict_refresh_key = gray_type.."refresh"
local dict_switch_key = gray_type.."switch"
local dict_userid_api_key = gray_type.."userid:api"
local dict_userid_wxappapi_key = gray_type.."userid:wxappapi"
local dict_userid_web_key = gray_type.."userid:web"
local dict_ip_api_key = gray_type.."ip:api"
local dict_ip_wxappapi_key = gray_type.."ip:wxappapi"
local dict_ip_web_key = gray_type.."ip:web"


-- get all cookies
function get_cookies()
  local cookies = ngx.header["Set-Cookie"] or {}
  if type(cookies) == "string" then
    cookies = {cookies}
  end
  return cookies
end

-- add cookie
function add_cookie(cookie)
  local cookies = get_cookies()
  table.insert(cookies, cookie)
  ngx.header['Set-Cookie'] = cookies
end

-- get userId
...skipping...
        
    if red then setKeepalive(red) end           
end

local ok,err = pcall(checkfunc)

-- gray policy
local policyfunc = function()
        local ups = nil
        local runtimeCache = cache:new(ngx.var.runtime)
        
        local switch = runtimeCache:getSwitch(dict_switch_key)
        if "off" == switch then
                return true,nil
        end
        
        -- use userid policy
        local userid = get_userid()
        if userid then 
                ups = runtimeCache:getUpstream(dict_userid_wxappapi_key..userid)
        end
        if ups then
                upstream = ups
                return true,ups
        end     
        
        -- use ip policy
        local ip = ipParser.get()       
        ups = runtimeCache:getUpstream(dict_ip_wxappapi_key..ip)
        if ups then
                upstream = ups
                return true,ups
        end
        
        return true,nil
end

local ok,ups = pcall(policyfunc)

if upstream then
        ngx.log(ngx.INFO, 'backend = '..upstream)
    ngx.var.backend = upstream
end

 

 

 

cookie.lua

[appdeploy@NG-GW1 resty]$ cat cookie.lua 
-- Copyright (C) 2013-2016 Jiale Zhi (calio), CloudFlare Inc.
-- See RFC6265 http://tools.ietf.org/search/rfc6265
-- require "luacov"

local type          = type
local byte          = string.byte
local sub           = string.sub
local format        = string.format
local log           = ngx.log
local ERR           = ngx.ERR
local WARN          = ngx.WARN
local ngx_header    = ngx.header

local EQUAL         = byte("=")
local SEMICOLON     = byte(";")
local SPACE         = byte(" ")
local HTAB          = byte("\t")

-- table.new(narr, nrec)
local ok, new_tab = pcall(require, "table.new")
if not ok then
    new_tab = function () return {} end
end

local ok, clear_tab = pcall(require, "table.clear")
if not ok then
    clear_tab = function(tab) for k, _ in pairs(tab) do tab[k] = nil end end
end

local _M = new_tab(0, 2)

_M._VERSION = '0.01'


local function get_cookie_table(text_cookie)
    if type(text_cookie) ~= "string" then
        log(ERR, format("expect text_cookie to be \"string\" but found %s",
                type(text_cookie)))
        return {}
    end

    local EXPECT_KEY    = 1
    local EXPECT_VALUE  = 2
    local EXPECT_SP     = 3

    local n = 0
    local len = #text_cookie

    for i=1, len do
        if byte(text_cookie, i) == SEMICOLON then
            n = n + 1
        end
    end

    local cookie_table  = new_tab(0, n + 1)

    local state = EXPECT_SP
    local i = 1
    local j = 1
    local key, value

    while j <= len do
        if state == EXPECT_KEY then
            if byte(text_cookie, j) == EQUAL then
                key = sub(text_cookie, i, j - 1)
                state = EXPECT_VALUE
                i = j + 1
            end
        elseif state == EXPECT_VALUE then
            if byte(text_cookie, j) == SEMICOLON
                    or byte(text_cookie, j) == SPACE
                    or byte(text_cookie, j) == HTAB
            then
                value = sub(text_cookie, i, j - 1)
                cookie_table[key] = value

                key, value = nil, nil
                state = EXPECT_SP
                i = j + 1
            end
        elseif state == EXPECT_SP then
            if byte(text_cookie, j) ~= SPACE
                and byte(text_cookie, j) ~= HTAB
            then
                state = EXPECT_KEY
                i = j
                j = j - 1
            end
        end
        j = j + 1
    end

    if key ~= nil and value == nil then
        cookie_table[key] = sub(text_cookie, i)
    end

    return cookie_table
end

function _M.new(self)
    local _cookie = ngx.var.http_cookie
    --if not _cookie then
        --return nil, "no cookie found in current request"
    --end
    return setmetatable({ _cookie = _cookie, set_cookie_table = new_tab(4, 0) },
        { __index = self })
end

function _M.get(self, key)
    if not self._cookie then
        return nil, "no cookie found in the current request"
    end
    if self.cookie_table == nil then
        self.cookie_table = get_cookie_table(self._cookie)
    end

    return self.cookie_table[key]
end

function _M.get_all(self)
    if not self._cookie then
        return nil, "no cookie found in the current request"
    end

    if self.cookie_table == nil then
        self.cookie_table = get_cookie_table(self._cookie)
    end

    return self.cookie_table
end

local function bake(cookie)
    if not cookie.key or not cookie.value then
        return nil, 'missing cookie field "key" or "value"'
    end

    if cookie["max-age"] then
        cookie.max_age = cookie["max-age"]
    end

    if (cookie.samesite) then
        local samesite = cookie.samesite

        -- if we dont have a valid-looking attribute, ignore the attribute
        if (samesite ~= "Strict" and samesite ~= "Lax") then
            log(WARN, "SameSite value must be 'Strict' or 'Lax'")
            cookie.samesite = nil
        end
    end

    local str = cookie.key .. "=" .. cookie.value
        .. (cookie.expires and "; Expires=" .. cookie.expires or "")
        .. (cookie.max_age and "; Max-Age=" .. cookie.max_age or "")
        .. (cookie.domain and "; Domain=" .. cookie.domain or "")
        .. (cookie.path and "; Path=" .. cookie.path or "")
        .. (cookie.secure and "; Secure" or "")
        .. (cookie.httponly and "; HttpOnly" or "")
        .. (cookie.samesite and "; SameSite=" .. cookie.samesite or "")
        .. (cookie.extension and "; " .. cookie.extension or "")
    return str
end

function _M.set(self, cookie)
    local cookie_str, err = bake(cookie)
    if not cookie_str then
        return nil, err
    end

    local set_cookie = ngx_header['Set-Cookie']
    local set_cookie_type = type(set_cookie)
    local t = self.set_cookie_table
    clear_tab(t)

    if set_cookie_type == "string" then
        -- only one cookie has been setted
        if set_cookie ~= cookie_str then
            t[1] = set_cookie
            t[2] = cookie_str
            ngx_header['Set-Cookie'] = t
        end
    elseif set_cookie_type == "table" then
        -- more than one cookies has been setted
        local size = #set_cookie

        -- we can not set cookie like ngx.header['Set-Cookie'][3] = val
        -- so create a new table, copy all the values, and then set it back
        for i=1, size do
            t[i] = ngx_header['Set-Cookie'][i]
            if t[i] == cookie_str then
                -- new cookie is duplicated
                return true
            end
        end
        t[size + 1] = cookie_str
        ngx_header['Set-Cookie'] = t
    else
        -- no cookie has been setted
        ngx_header['Set-Cookie'] = cookie_str
    end
    return true
end

return _M

 

redis.lua

[appdeploy@NG-GW1 resty]$ cat redis.lua 
-- Copyright (C) Yichun Zhang (agentzh)


local sub = string.sub
local byte = string.byte
local tcp = ngx.socket.tcp
local null = ngx.null
local type = type
local pairs = pairs
local unpack = unpack
local setmetatable = setmetatable
local tonumber = tonumber
local tostring = tostring
local rawget = rawget
--local error = error


local ok, new_tab = pcall(require, "table.new")
if not ok or type(new_tab) ~= "function" then
    new_tab = function (narr, nrec) return {} end
end


local _M = new_tab(0, 54)

_M._VERSION = '0.26'


local common_cmds = {
    "get",      "set",          "mget",     "mset",
    "del",      "incr",         "decr",                 -- Strings
    "llen",     "lindex",       "lpop",     "lpush",
    "lrange",   "linsert",                              -- Lists
    "hexists",  "hget",         "hset",     "hmget",
    --[[ "hmset", ]]            "hdel",                 -- Hashes
    "smembers", "sismember",    "sadd",     "srem",
    "sdiff",    "sinter",       "sunion",               -- Sets
    "zrange",   "zrangebyscore", "zrank",   "zadd",
    "zrem",     "zincrby",                              -- Sorted Sets
    "auth",     "eval",         "expire",   "script",
    "sort"                                              -- Others
}


local sub_commands = {
    "subscribe", "psubscribe"
}


local unsub_commands = {
    "unsubscribe", "punsubscribe"
}


local mt = { __index = _M }


function _M.new(self)
    local sock, err = tcp()
    if not sock then
        return nil, err
    end
    return setmetatable({ _sock = sock, _subscribed = false }, mt)
end


function _M.set_timeout(self, timeout)
    local sock = rawget(self, "_sock")
    if not sock then
        return nil, "not initialized"
    end

    return sock:settimeout(timeout)
end


function _M.connect(self, ...)
    local sock = rawget(self, "_sock")
    if not sock then
        return nil, "not initialized"
    end

    self._subscribed = false

    return sock:connect(...)
end


function _M.set_keepalive(self, ...)
    local sock = rawget(self, "_sock")
    if not sock then
        return nil, "not initialized"
    end

    if rawget(self, "_subscribed") then
        return nil, "subscribed state"
    end

    return sock:setkeepalive(...)
end


function _M.get_reused_times(self)
    local sock = rawget(self, "_sock")
    if not sock then
        return nil, "not initialized"
    end

    return sock:getreusedtimes()
end


local function close(self)
    local sock = rawget(self, "_sock")
    if not sock then
        return nil, "not initialized"
    end

    return sock:close()
end
_M.close = close


local function _read_reply(self, sock)
    local line, err = sock:receive()
    if not line then
        if err == "timeout" and not rawget(self, "_subscribed") then
            sock:close()
        end
        return nil, err
    end

    local prefix = byte(line)

    if prefix == 36 then    -- char '$'
        -- print("bulk reply")

        local size = tonumber(sub(line, 2))
        if size < 0 then
            return null
        end

        local data, err = sock:receive(size)
        if not data then
            if err == "timeout" then
                sock:close()
            end
            return nil, err
        end

        local dummy, err = sock:receive(2) -- ignore CRLF
        if not dummy then
            return nil, err
        end

        return data

    elseif prefix == 43 then    -- char '+'
        -- print("status reply")

        return sub(line, 2)

    elseif prefix == 42 then -- char '*'
        local n = tonumber(sub(line, 2))

        -- print("multi-bulk reply: ", n)
        if n < 0 then
            return null
        end

        local vals = new_tab(n, 0)
        local nvals = 0
        for i = 1, n do
            local res, err = _read_reply(self, sock)
            if res then
                nvals = nvals + 1
                vals[nvals] = res

            elseif res == nil then
                return nil, err

            else
                -- be a valid redis error value
                nvals = nvals + 1
                vals[nvals] = {false, err}
            end
        end

        return vals

    elseif prefix == 58 then    -- char ':'
        -- print("integer reply")
        return tonumber(sub(line, 2))

    elseif prefix == 45 then    -- char '-'
        -- print("error reply: ", n)

        return false, sub(line, 2)

    else
        -- when `line` is an empty string, `prefix` will be equal to nil.
        return nil, "unknown prefix: \"" .. tostring(prefix) .. "\""
    end
end


local function _gen_req(args)
    local nargs = #args

    local req = new_tab(nargs * 5 + 1, 0)
    req[1] = "*" .. nargs .. "\r\n"
    local nbits = 2

    for i = 1, nargs do
        local arg = args[i]
        if type(arg) ~= "string" then
            arg = tostring(arg)
        end

        req[nbits] = "$"
        req[nbits + 1] = #arg
        req[nbits + 2] = "\r\n"
        req[nbits + 3] = arg
        req[nbits + 4] = "\r\n"

        nbits = nbits + 5
    end

    -- it is much faster to do string concatenation on the C land
    -- in real world (large number of strings in the Lua VM)
    return req
end


local function _do_cmd(self, ...)
    local args = {...}

    local sock = rawget(self, "_sock")
    if not sock then
        return nil, "not initialized"
    end

    local req = _gen_req(args)

    local reqs = rawget(self, "_reqs")
    if reqs then
        reqs[#reqs + 1] = req
        return
    end

    -- print("request: ", table.concat(req))

    local bytes, err = sock:send(req)
    if not bytes then
        return nil, err
    end

    return _read_reply(self, sock)
end


local function _check_subscribed(self, res)
    if type(res) == "table"
       and (res[1] == "unsubscribe" or res[1] == "punsubscribe")
       and res[3] == 0
   then
        self._subscribed = false
    end
end


function _M.read_reply(self)
    local sock = rawget(self, "_sock")
    if not sock then
        return nil, "not initialized"
    end

    if not rawget(self, "_subscribed") then
        return nil, "not subscribed"
    end

    local res, err = _read_reply(self, sock)
    _check_subscribed(self, res)

    return res, err
end


for i = 1, #common_cmds do
    local cmd = common_cmds[i]

    _M[cmd] =
        function (self, ...)
            return _do_cmd(self, cmd, ...)
        end
end


for i = 1, #sub_commands do
    local cmd = sub_commands[i]

    _M[cmd] =
        function (self, ...)
            self._subscribed = true
            return _do_cmd(self, cmd, ...)
        end
end


for i = 1, #unsub_commands do
    local cmd = unsub_commands[i]

    _M[cmd] =
        function (self, ...)
            local res, err = _do_cmd(self, cmd, ...)
            _check_subscribed(self, res)
            return res, err
        end
end


function _M.hmset(self, hashname, ...)
    if select('#', ...) == 1 then
        local t = select(1, ...)

        local n = 0
        for k, v in pairs(t) do
            n = n + 2
        end

        local array = new_tab(n, 0)

        local i = 0
        for k, v in pairs(t) do
            array[i + 1] = k
            array[i + 2] = v
            i = i + 2
        end
        -- print("key", hashname)
        return _do_cmd(self, "hmset", hashname, unpack(array))
    end

    -- backwards compatibility
    return _do_cmd(self, "hmset", hashname, ...)
end


function _M.init_pipeline(self, n)
    self._reqs = new_tab(n or 4, 0)
end


function _M.cancel_pipeline(self)
    self._reqs = nil
end


function _M.commit_pipeline(self)
    local reqs = rawget(self, "_reqs")
    if not reqs then
        return nil, "no pipeline"
    end

    self._reqs = nil

    local sock = rawget(self, "_sock")
    if not sock then
        return nil, "not initialized"
    end

    local bytes, err = sock:send(reqs)
    if not bytes then
        return nil, err
    end

    local nvals = 0
    local nreqs = #reqs
    local vals = new_tab(nreqs, 0)
    for i = 1, nreqs do
        local res, err = _read_reply(self, sock)
        if res then
            nvals = nvals + 1
            vals[nvals] = res

        elseif res == nil then
            if err == "timeout" then
                close(self)
            end
            return nil, err

        else
            -- be a valid redis error value
            nvals = nvals + 1
            vals[nvals] = {false, err}
        end
    end

    return vals
end


function _M.array_to_hash(self, t)
    local n = #t
    -- print("n = ", n)
    local h = new_tab(0, n / 2)
    for i = 1, n, 2 do
        h[t[i]] = t[i + 1]
    end
    return h
end


-- this method is deperate since we already do lazy method generation.
function _M.add_commands(...)
    local cmds = {...}
    for i = 1, #cmds do
        local cmd = cmds[i]
        _M[cmd] =
            function (self, ...)
                return _do_cmd(self, cmd, ...)
            end
    end
end


setmetatable(_M, {__index = function(self, cmd)
    local method =
        function (self, ...)
            return _do_cmd(self, cmd, ...)
        end

    -- cache the lazily generated method in our
    -- module table
    _M[cmd] = method
    return method
end})


return _M

  

 

 

cache.lua 

[appdeploy@NG-GW1 utils]$ cat cache.lua 
local modulename = "fezsgrayCache"

local _M = {}
_M._VERSION = '0.0.1'

local shdict_expire = 60
local upstream_expire = 180

_M.new = function(self, sharedDict)
    if not sharedDict then
		ngx.log(ngx.ERR, 'cache name valid from nginx.conf')
    end

    self.cache = ngx.shared[sharedDict]
    if not self.cache then
		ngx.log(ngx.ERR, 'cache name [' .. sharedDict .. '] valid from nginx.conf')
    end

    return setmetatable(self, { __index = _M } )
end

local isNULL = function(v)
    return not v or v == ngx.null
end

_M.getRefreshFlag = function(self, key)
	local cache  = self.cache
    local value   = cache:get(key)	
	if isNULL(value) then
		return nil
	end	
    return value
end

_M.setRefreshFlag = function(self, key)
    local cache  = self.cache
    local expire = shdict_expire
	if key then
		cache:set(key, 'no', expire)
	end    
end

_M.getUpstream = function(self, info)
	local cache  = self.cache
    local upstream = nil
    local ups   = cache:get(info)	
	if not isNULL(ups) then
		upstream = ups
	end	
    return upstream
end

_M.setUpstream = function(self, info, upstream)
    local cache  = self.cache
    local expire = upstream_expire
	if info then
		cache:set(info, upstream, expire)
	end    
end

_M.getSwitch = function(self, key)
	local cache  = self.cache
    local value = nil
    local tmp = cache:get(key)	
	if not isNULL(tmp) then
		value = tmp
	end	
    return value
end

_M.setSwitch= function(self, key, value)
    local cache  = self.cache
    local expire = shdict_expire
	if key then
		cache:set(key, value, expire)
	end    
end

return _M

  

init.lua 

[appdeploy@NG-GW1 utils]$ cat init.lua 
local modulename = "fezsgrayInit"
local _M = {}

_M._VERSION = '0.0.1'

_M.redisConf = {
    ["host"]     = ngx.var.redis_host,
    ["port"]     = ngx.var.redis_port,
    ["password"] = ngx.var.redis_password,
    ["poolsize"] = ngx.var.redis_pool_size,
    ["idletime"] = ngx.var.redis_keepalive_timeout ,
    ["timeout"]  = ngx.var.redis_connect_timeout,
    ["dbid"]     = ngx.var.redis_dbid,
}

return _M

  

ipParser.lua 

[appdeploy@NG-GW1 utils]$ cat ipParser.lua 

local _M = {
    _VERSION = '0.01'
}

local ffi = require("ffi")

ffi.cdef[[
struct in_addr {
    uint32_t s_addr;
};

int inet_aton(const char *cp, struct in_addr *inp);
uint32_t ntohl(uint32_t netlong);

char *inet_ntoa(struct in_addr in);
uint32_t htonl(uint32_t hostlong);
]]

local C = ffi.C

local ip2long = function(ip)
    local inp = ffi.new("struct in_addr[1]")
    if C.inet_aton(ip, inp) ~= 0 then
        return tonumber(C.ntohl(inp[0].s_addr))
    end
    return nil
end

local long2ip = function(long)
    if type(long) ~= "number" then
        return nil
    end
    local addr = ffi.new("struct in_addr")
    addr.s_addr = C.htonl(long)
    return ffi.string(C.inet_ntoa(addr))
end



_M.get = function()
	local ClientIP = ngx.req.get_headers()["X-Forwarded-For"]

	if ClientIP then
		local i,j = string.find(ClientIP, ',')
		if i then
			ClientIP = string.sub(ClientIP, 1, i - 1)
		end
	end

    if ClientIP == nil then
        ClientIP = ngx.req.get_headers()["X-Real-IP"]
    end

    if ClientIP == nil then
        ClientIP = ngx.var.remote_addr
    end

    --if ClientIP then 
    --    ClientIP = ip2long(ClientIP)
    --end
    return ClientIP
end


return _M

  

 

 

redis.lua

[appdeploy@NG-GW1 utils]$ cat redis.lua 
local modulename = "fezsgrayRedis"
local _M = {}

_M._VERSION = '0.0.1'

local redis = require('resty.redis')

_M.new = function(self, conf)
    self.host       = conf.host
    self.port       = conf.port
    self.password   = conf.password
    self.timeout    = conf.timeout
    self.dbid       = conf.dbid
    self.poolsize   = conf.poolsize
    self.idletime   = conf.idletime

    local red = redis:new()
    return setmetatable({redis = red}, { __index = _M } )
end

_M.connectdb = function(self)

    local host  = self.host
    local port  = self.port
    local password  = self.password
    local dbid  = self.dbid
    local red   = self.redis
   
    if not dbid then 
		dbid = 0 
	end

    local timeout   = self.timeout 
    if not timeout then 
        timeout = 10000   -- 10s
    end
    red:set_timeout(timeout)

    local ok, err  
    if host and port then
        ok, err = red:connect(host, port)
	if not ok then
                return false, err
        end

        local count
        count, err = red:get_reused_times()
        if 0 == count then
                ok, err = red:auth(password)
                if not ok then
                        return false, err
                end
        elseif err then
                return false, err
        end

        if ok then 
		return red:select(dbid) 
	end
    end

    return ok, err
end


_M.keepalivedb = function(self)
    local   pool_max_idle_time  = self.idletime --毫秒
    local   pool_size           = self.poolsize --连接池大小

    if not pool_size then pool_size = 1000 end
    if not pool_max_idle_time then pool_max_idle_time = 90000 end
    
    return self.redis:set_keepalive(pool_max_idle_time, pool_size)  
end

return _M

  

posted @ 2019-03-13 14:24  Gringer  阅读(372)  评论(0)    收藏  举报