灰度发布-Openresty+lua实现动态upstream

动态的负载均衡控制;
平滑上下线服务,升级服务;
高可能保证–自动踢离线服务下线;
具体思路
利用lua中 "lua_shared_dict" 指令开辟一个共享内存空间;
通过API动态根据key值&参数修改 upstream (这里使用 host 作为key);
利用 proxy_pass 可使用变量特性及lua指令 "set_by_lua" 动态修改当前 upstream 变量即可;
配置:

worker_processes  1;
pid        logs/nginx.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 "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';
    sendfile        on;
 
    keepalive_timeout  65;
          
    #lua_shared_dict upstreams 1m;  # 声明一个ngx多进程全局共享内存区域,_G 作为基于shm的Lua字典的存储空间ngx.shared.<name>   
    lua_shared_dict _ups_zone 64m; # 定义upstream共享内存空间
 
 
        
    upstream backend {                        # 配置后端服务器组
                server 127.0.0.1:18084;
                server 127.0.0.1:18083;
    }
 
    server {
        listen       8000;
        server_name  localhost;
 
        access_log  logs/80.access.log  main;
        error_log   logs/80.error.log error;
 
 
#更新API接口
        location = /ups_update {  
            content_by_lua '  
                local ups = ngx.req.get_uri_args()["ups"]  
                if ups == nil then 
                    ngx.say("usage: /ups_update?ups=x.x.x.x")  
                    return 
                end  
                local host = ngx.var.http_host  
                local ups_from = ngx.shared._ups_zone:get(host);  
                ngx.log(ngx.WARN, host, " update upstream from ", ups_from, " to ", ups)  
                ngx.shared._ups_zone:set(host, ups);  
                ngx.say(host, " update upstream from ", ups_from, " to ", ups)  
            ';  
        }
 
location / {  
            # 动态设置当前 upstream, 未设置则使用默认 upstream  
            set_by_lua $cur_ups '  
                local ups = ngx.shared._ups_zone:get(ngx.var.http_host)  
                if ups ~= nil then 
                    ngx.log(ngx.ERR, "get [", ups, "] from ngx.shared._ups_zone")  
                    return ups  
                end  
                --ngx.log(ngx.INFO, "use default upstream");  
                return "qq_backend";  
            '  
            proxy_next_upstream off;  
            proxy_set_header    Host $host;  
            proxy_http_version  1.1;  
            proxy_set_header    Connection  "";  
            proxy_pass $scheme://$cur_ups;  
        }
 
 
}
 

}

测试切换upstream的backend效果:
1、默认情况【请求4次】:

root@ubuntu:~# curl  127.0.0.1:8000
83 server
root@ubuntu:~# curl  127.0.0.1:8000
84 server 
root@ubuntu:~# curl  127.0.0.1:8000
83 server
root@ubuntu:~# curl  127.0.0.1:8000
84 server 

切换upstream

root@ubuntu:~# curl  127.0.0.1:8000/ups_update?ups=127.0.0.1:18083
127.0.0.1:8000 update upstream from 127.0.0.1:18083 to 127.0.0.1:18083
root@ubuntu:~# curl  127.0.0.1:8000
83 server
root@ubuntu:~# curl  127.0.0.1:8000
83 server
root@ubuntu:~# curl  127.0.0.1:8000
83 server
root@ubuntu:~# curl  127.0.0.1:8000
83 server

切换upstream:

worker_processes  1;
pid        logs/nginx.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 "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';
    sendfile        on;
 
    keepalive_timeout  65;
          
    lua_shared_dict upstreams 1m;  # 声明一个ngx多进程全局共享内存区域,_G 作为基于shm的Lua字典的存储空间ngx.shared.<name>   
    upstream default_upstream {                        # 配置后端服务器组
                server 127.0.0.1:18081;
                server 127.0.0.1:18082;
    }
         
    upstream lua_upstream {                        # 配置后端服务器组
                server 127.0.0.1:18084;
                server 127.0.0.1:18083;
    }
 
    server {
        listen       8000;
        server_name  localhost;
 
        access_log  logs/80.access.log  main;
        error_log   logs/80.error.log error;
 
        location = /_switch_upstream {
             content_by_lua_block{
                    local ups = ngx.req.get_uri_args()["upstream"]
                    if ups == nil or ups == "" then
                        ngx.say("upstream is nil 1")
                        return nil
                    end
                    local host = ngx.var.http_host
                    local upstreams = ngx.shared.upstreams
                    local ups_src = upstreams:get(host)
                    ngx.say("Current upstream is :",ups_src)
                    ngx.log(ngx.WARN, host, " change upstream from ", ups_src, " to ", ups)
                    local succ, err, forcible = upstreams:set(host,  ups)
                    ngx.say(host, " change upstream from ", ups_src, " to ", ups)
            }
        }
         
        location / {
            set_by_lua_block $my_upstream {
                local ups = ngx.shared.upstreams:get(ngx.var.http_host)
                if ups ~= nil then
                    ngx.log(ngx.ERR, "get [", ups,"] from ngx.shared")
                    return ups
                end
                return "default_upstream"
            }
 
            proxy_next_upstream off;
            proxy_set_header    X-Real-IP           $remote_addr;
            proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
            proxy_set_header    Host                $host;
            proxy_http_version  1.1;
            proxy_set_header    Connection  "";
            proxy_pass          http://$my_upstream ;
        }
    }   
 
   
}

切换:

curl 127.0.0.1:8000/_switch_upstream?upstream=lua_upstream
curl 127.0.0.1:8000/_switch_upstream?upstream=default_upstream

这里用的还是静态文件,改成tomcat服务之后也是可以进行代理的切换。要是想持久化的话 ,得用到redis。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,012评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,589评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,819评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,652评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,954评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,381评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,687评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,404评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,082评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,355评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,880评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,249评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,864评论 3 232
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,007评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,760评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,394评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,281评论 2 259

推荐阅读更多精彩内容