大家都知道,nginx是当前应用非常广泛的web服务器,热度因为他的高并发高性能高可靠性,且轻量级!牛逼的不行,不多说这些。

今天要介绍的是,如何基于nginx和lua脚本,也就是在openresty的环境下,实现动态的反向代理逻辑,有一个开关控制。开关控制反向代理工作在nginx原生的upstream的模式,还是工作在lua控制的动态代理模式。 动态代理的服务器,通过http请求实现灵活的操作,向lua_shared_dict定义的全局变量里面写入或者删除动态代理的服务器信息。

环境信息如下:

 [root@bogon sbin]# ./nginx -V
nginx version: openresty/1.11.2.2
built by gcc 4.8. (Red Hat 4.8.-) (GCC)
built with OpenSSL 1.0.1e-fips Feb
TLS SNI support enabled
configure arguments: --prefix=/usr/local/openresty/nginx --with-cc-opt=-O2 --add-module=../ngx_devel_kit-0.3. --add-module=../echo-nginx-module-0.60 --add-module=../xss-nginx-module-0.05 --add-module=../ngx_coolkit-.2rc3 --add-module=../set-misc-nginx-module-0.31 --add-module=../form-input-nginx-module-0.12 --add-module=../encrypted-session-nginx-module-0.06 --add-module=../srcache-nginx-module-0.31 --add-module=../ngx_lua-0.10. --add-module=../ngx_lua_upstream-0.06 --add-module=../headers-more-nginx-module-0.32 --add-module=../array-var-nginx-module-0.05 --add-module=../memc-nginx-module-0.17 --add-module=../redis2-nginx-module-0.13 --add-module=../redis-nginx-module-0.3. --add-module=../rds-json-nginx-module-0.14 --add-module=../rds-csv-nginx-module-0.07 --with-ld-opt=-Wl,-rpath,/usr/local/openresty/luajit/lib --add-module=/opt/nginx-rtmp-module-master --with-http_ssl_module

先设计一下功能模块,在nginx.conf文件里面,有如下几个location:

location / {。。。}
业务逻辑的入口 location /config {。。。}
动态反向代理开关控制入口 location /add_ups {。。。}
添加反向代理的服务器信息进入lua_shared_dict定义的全局表单 location /stop_ups {。。。}
从lua_shared_dict定义的全局表单里面删除掉不再参与反向代理的服务器信息 location /check_ups {。。。}
查看当前lua_shared_dict定义的全局表单里面有那些服务器信息

为了验证这个设计,我在本地开发机器上,将同一个RDConsumer应用部署在3个不同的端口下,对应于nginx里面的upstream块:

upstream robot_ups {
server 10.90.9.20:;
server 10.90.9.20:;
server 10.90.9.20:;
}

在这里,强调一下,这里,我们验证的动态反向代理,是轮询的方式,当然,根据需要可以设计成符合各自业务的逻辑。

下面,对这个设计的全部过程进行详细介绍。若有需要,可以用起来或者转走,觉得好,还可以点个赞,或者加个关注

1. nginx.conf的配置文件

#user  nobody;
worker_processes ; error_log logs/error.log;
error_log logs/error.log notice;
error_log logs/error.log info; #pid logs/nginx.pid; events {
worker_connections ;
use epoll;
} http {
lua_shared_dict dyn_ups_zone 10m; 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"'; #access_log logs/access.log main; sendfile on;
#tcp_nopush on; #keepalive_timeout ;
keepalive_timeout ; #gzip on; upstream robot_ups {
server 10.90.9.20:;
server 10.90.9.20:;
server 10.90.9.20:;
} server {
listen ;
server_name localhost; #charset koi8-r; location / {
set_by_lua_file $cur_ups /opt/shihuc/luahome/ablb/bussups.lua
proxy_next_upstream off;
proxy_set_header Host $host:$server_port;
proxy_set_header Remote_Addr $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://$cur_ups;
} location /config {
default_type text/plain;
content_by_lua_block {
local foo = ngx.req.get_uri_args()["foo"]
if foo == nil then
ngx.say("usage: /config?foo=off, or /config?foo=on")
return;
end
ngx.log(ngx.INFO, "config ab deploy feature: ", foo);
ngx.say("config ab deploy feature: ", foo); ngx.shared.dyn_ups_zone:set("robotfoo", foo);
}
} location /stop_ups {
default_type text/plain;
content_by_lua_file /opt/shihuc/luahome/ablb/stopups.lua;
} location /add_ups {
default_type text/plain;
content_by_lua_block {
local add_s = ngx.req.get_uri_args()["ups"]
if add_s == nil then
ngx.say("usage: /add_ups?ups=x.x.x.x")
return "no add_s"
end
ngx.log(ngx.INFO, "add upstream server: ", add_s);
local dynupszone = ngx.shared.dyn_ups_zone;
local ups = dynupszone:get("robotups");
if ups == nil then
ngx.say("first init global dict dyn_ups_zone");
ups = add_s
else
local unders = "-";
ups = ups..unders
ups = ups..add_s
end
local succ, err, forcible = dynupszone:set("robotups", ups);
ngx.say("succ: ",succ, ", err: ", err, ", forcible: ", forcible);
ngx.say(dynupszone.get(dynupszone, "robotups"))
}
} location /check_ups {
default_type text/plain;
content_by_lua_block {
local dynupszone = ngx.shared.dyn_ups_zone;
local ups = dynupszone:get("robotups");
ngx.say(ups);
}
} error_page /50x.html;
location = /50x.html {
root html;
}
}
}

2. 调用add_ups url向全局缓存lua_shared_dict dyn_ups_zone 10m填写数据。

对应的后台日志如下:

// :: [info] #: * [lua] content_by_lua(nginx.conf:):: add upstream server: 10.90.9.20:, client: 10.90.9.20, server: localhost, request: "GET /add_ups?ups=10.90.9.20:8081 HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] content_by_lua(nginx.conf:):: add upstream server: 10.90.9.20:, client: 10.90.9.20, server: localhost, request: "GET /add_ups?ups=10.90.9.20:8090 HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] content_by_lua(nginx.conf:):: add upstream server: 10.90.9.20:, client: 10.90.9.20, server: localhost, request: "GET /add_ups?ups=10.90.9.20:9080 HTTP/1.1", host: "10.90.7.10"

3. config配置灰度启用

日志请参考:

// :: [info] #: * [lua] content_by_lua(nginx.conf:):: config ab deploy feature: on, client: 10.90.9.20, server: localhost, request: "GET /config?foo=on HTTP/1.1", host: "10.90.7.10"

4. 在不做灰度停用机器的时候,看看请求如何调度。这里,我的测试应用在本地部署了3个,端口区分。在10.90.7.10这个nginx上做反向代理,轮询分发请求。我执行了4次请求,通过restlet client (chrome的一个http模拟插件),nginx的后台日志如下:

// :: [info] #: * [lua] bussups.lua:: ups: 10.90.9.20:-10.90.9.20:-10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: foo: on, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: cnt: nil, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: ups list: 10.90.9.20:-10.90.9.20:-10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: idx: , exc: ,current ups: 10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: ups: 10.90.9.20:-10.90.9.20:-10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: foo: on, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: cnt: , client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: ups list: 10.90.9.20:-10.90.9.20:-10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: idx: , exc: ,current ups: 10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: ups: 10.90.9.20:-10.90.9.20:-10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: foo: on, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: cnt: , client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: ups list: 10.90.9.20:-10.90.9.20:-10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: idx: , exc: ,current ups: 10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: ups: 10.90.9.20:-10.90.9.20:-10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: foo: on, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: cnt: , client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: ups list: 10.90.9.20:-10.90.9.20:-10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: idx: , exc: ,current ups: 10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"

从日志看,轮询是没有问题的。轮询的依据,是在nginx的全局变量dyn_ups_zone里面定义了一个cnt的变量,记录请求次数。请求数与当前反向代理里面的机器数量求模。用余数作为lua列表的下标,求出服务器IP端口信息。作为反向代理的机器。
这里要注意的是:
a. lua数组或者列表下标不是从0开始,而是1.
b. lua数组的下标,可以是不同数据类型的值,不像java等高级语言,是数字下标。

5. 停用一台服务器,通过stop_ups调用。然后查看反向代理跳转是否生效。

发现stop操作,有点问题,请看下图,原来3个应用,停了中间一个,最后的ups列表中怎么只有一个应用服务器信息了?先看看stopups.lua的脚本吧:

#!/usr/bin/env lua

function split(s, delim)
if type(delim) ~= "string" or string.len(delim) <= then
return
end local start =
local t = {}
while true do
local pos = string.find (s, delim, start, true) -- plain find
if not pos then
break
end table.insert (t, string.sub (s, start, pos - ))
start = pos + string.len (delim)
end
table.insert (t, string.sub (s, start)) return t
end local stop_s = ngx.req.get_uri_args()["ups"];
if stop_s == nil then
ngx.say("usage: /stop_ups?ups=x.x.x.x");
return "no stop_s"
end
ngx.say("stop upstream server: ", stop_s);
local dynupszone = ngx.shared.dyn_ups_zone;
local ups = dynupszone:get("robotups");
if ups == nil then
ngx.say("currently, there is no server ip to stop...");
return;
end
local table_ups = split(ups, "-");
ngx.say(table_ups);
local delid=;
for k,v in ipairs(table_ups) do
ngx.say("key: ",k,", value: ", v);
if v == stop_s then
delid = k;
end
end
table_ups[delid] = nil;
ngx.say(table_ups);
local new_ups = table.concat(table_ups,"-");
ngx.say("new ups: ", new_ups);
dynupszone:set("robotups",new_ups);

分析一下,发现,table数据table_ups里面设置nil的值,其实也是可以的。但是,在做table.concat的时候,会将第一个nil作为数据拼接的结束标识了,于是nil后面的数据不被计入。调整一下统计余下应用服务器信息的算法。调整后如下(local table_ups = split(ups, "-");代码之前的不变):

local table_ups = split(ups, "-");
ngx.say(table_ups);
local new_table_ups = {}
for k,v in ipairs(table_ups) do
ngx.say("key: ",k,", value: ", v);
if v ~= stop_s then
table.insert(new_table_ups, v);
end
end
ngx.say(new_table_ups);
local new_ups = table.concat(new_table_ups,"-");
ngx.say("new ups: ", new_ups);
dynupszone:set("robotups",new_ups);

重复前面的操作,再进行stop_ups,就得到合理的结果,如图:

在模拟发送请求4次,看看日志:

// :: [info] #: * [lua] bussups.lua:: ups: 10.90.9.20:-10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: foo: on, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: cnt: nil, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: ups list: 10.90.9.20:-10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: idx: , exc: ,current ups: 10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: ups: 10.90.9.20:-10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: foo: on, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: cnt: , client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: ups list: 10.90.9.20:-10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: idx: , exc: ,current ups: 10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: ups: 10.90.9.20:-10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: foo: on, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: cnt: , client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: ups list: 10.90.9.20:-10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: idx: , exc: ,current ups: 10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: ups: 10.90.9.20:-10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: foo: on, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: cnt: , client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: ups list: 10.90.9.20:-10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: idx: , exc: ,current ups: 10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"

从日志看,现在ups的服务器只有2个了,刚才stop掉的一个,不再了。执行4次请求,分别在余下的2个服务器之间轮询。合乎逻辑设计。

6. 关闭灰度发布的开发,执行config?foo=off。参考题config_off,nginx的后台日志如下:

// :: [info] #: * [lua] content_by_lua(nginx.conf:):: config ab deploy feature: off, client: 10.90.9.20, server: localhost, request: "GET /config?foo=off HTTP/1.1", host: "10.90.7.10"

7. 在关闭灰度开关的情况下,看看反向代理的逻辑。主要看看后台日志:

第1次请求:

// :: [info] #: * [lua] bussups.lua:: ups: 10.90.9.20:-10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: foo: off, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: cnt: , client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: use default upstream, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"

从部署的3台应用服务器上来看,这次调度到8089端口的应用了。

第2次请求:

// :: [info] #: * [lua] bussups.lua:: ups: 10.90.9.20:-10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: foo: off, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: cnt: , client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: use default upstream, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"

从部署的3台应用服务器上来看,这次调度到8081端口的应用了。

第3次请求:

// :: [info] #: * [lua] bussups.lua:: ups: 10.90.9.20:-10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: foo: off, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: cnt: , client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: use default upstream, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"

从部署的3台应用服务器上来看,这次调度到9080端口的应用了。

基于上面3次foo=off的模拟调用来看,程序运行于upstream模块的轮询模式。这个时候全局变量ups里面只有2个服务器应用。

8. 将刚才灰度停用的服务器8090加回来,再次启用foo=on,动态轮询验证。

// :: [info] #: * [lua] content_by_lua(nginx.conf:):: add upstream server: 10.90.9.20:, client: 10.90.9.20, server: localhost, request: "GET /add_ups?ups=10.90.9.20:8090 HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] content_by_lua(nginx.conf:):: config ab deploy feature: on, client: 10.90.9.20, server: localhost, request: "GET /config?foo=on HTTP/1.1", host: "10.90.7.10" // :: [info] #: * [lua] bussups.lua:: ups: 10.90.9.20:-10.90.9.20:-10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: foo: on, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: cnt: , client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: ups list: 10.90.9.20:-10.90.9.20:-10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: idx: , exc: ,current ups: 10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: ups: 10.90.9.20:-10.90.9.20:-10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: foo: on, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: cnt: , client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: ups list: 10.90.9.20:-10.90.9.20:-10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: idx: , exc: ,current ups: 10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: ups: 10.90.9.20:-10.90.9.20:-10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: foo: on, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: cnt: , client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: ups list: 10.90.9.20:-10.90.9.20:-10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: idx: , exc: ,current ups: 10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: ups: 10.90.9.20:-10.90.9.20:-10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: foo: on, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: cnt: , client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: ups list: 10.90.9.20:-10.90.9.20:-10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"
// :: [info] #: * [lua] bussups.lua:: idx: , exc: ,current ups: 10.90.9.20:, client: 10.90.9.20, server: localhost, request: "POST /RDConsumer/httpclient/conrst HTTP/1.1", host: "10.90.7.10"

从nginx日志以及应用程序的后台日志看,灰度的负载均衡方向代理逻辑,依然正常。

到此,整个验证完美收官!下面,附上,nginx.conf配置中涉及到的几个lua的脚本文件:

bussups.lua:

#!/usr/bin/env lua

function split(s, delim)
if type(delim) ~= "string" or string.len(delim) <= then
return
end local start =
local t = {}
while true do
local pos = string.find (s, delim, start, true) -- plain find
if not pos then
break
end table.insert (t, string.sub (s, start, pos - ))
start = pos + string.len (delim)
end
table.insert (t, string.sub (s, start)) return t
end local ups = ngx.shared.dyn_ups_zone:get("robotups");
local foo = ngx.shared.dyn_ups_zone:get("robotfoo");
local cnt = ngx.shared.dyn_ups_zone:get("robotcnt");
ngx.log(ngx.INFO, "ups: ", ups);
ngx.log(ngx.INFO, "foo: ", foo);
ngx.log(ngx.INFO, "cnt: ", cnt); if cnt == nil then
cnt = ;
end
ngx.shared.dyn_ups_zone:set("robotcnt", cnt+); if foo == "on" then
if ups ~= nil then
--ngx.log(ngx.info, "get robotups server list: ", ups)
ngx.log(ngx.INFO, "ups list: ", ups);
local table_ups = split(ups, "-");
local exc = ;
for k,v in ipairs(table_ups) do
exc = exc + ;
end
local idx = cnt % exc;
if idx == then --lua array index from , not from
idx = exc;
end
local cur_ups = table_ups[idx];
ngx.log(ngx.INFO, "idx: ", idx, ", exc: ", exc, " ,current ups: ", cur_ups);
return cur_ups
end
ngx.log(ngx.INFO, "ab lb configuration error, use default upstream");
return "robot_ups";
else
ngx.log(ngx.INFO, "use default upstream");
return "robot_ups";
end

stopups.lua:

#!/usr/bin/env lua

function split(s, delim)
if type(delim) ~= "string" or string.len(delim) <= then
return
end local start =
local t = {}
while true do
local pos = string.find (s, delim, start, true) -- plain find
if not pos then
break
end table.insert (t, string.sub (s, start, pos - ))
start = pos + string.len (delim)
end
table.insert (t, string.sub (s, start)) return t
end local stop_s = ngx.req.get_uri_args()["ups"];
if stop_s == nil then
ngx.say("usage: /stop_ups?ups=x.x.x.x");
return "no stop_s"
end
ngx.say("stop upstream server: ", stop_s);
local dynupszone = ngx.shared.dyn_ups_zone;
local ups = dynupszone:get("robotups");
if ups == nil then
ngx.say("currently, there is no server ip to stop...");
return;
end
local table_ups = split(ups, "-");
ngx.say(table_ups);
local new_table_ups = {}
for k,v in ipairs(table_ups) do
ngx.say("key: ",k,", value: ", v);
if v ~= stop_s then
table.insert(new_table_ups, v);
end
end
ngx.say(new_table_ups);
local new_ups = table.concat(new_table_ups,"-");
ngx.say("new ups: ", new_ups);
dynupszone:set("robotups",new_ups);

nginx功能强大,配合上lua脚本,在ngx_lua模块的存在下,功能就更加强大。感兴趣的话,可以加我关注哟,我们一起探讨!

基于nginx + lua实现的反向代理动态更新的更多相关文章

  1. 【架构师之路】Nginx负载均衡与反向代理—《亿级流量网站架构核心技术》

    本篇摘自<亿级流量网站架构核心技术>第二章 Nginx负载均衡与反向代理 部分内容. 当我们的应用单实例不能支撑用户请求时,此时就需要扩容,从一台服务器扩容到两台.几十台.几百台.然而,用 ...

  2. 基于nginx+lua+redis高性能api应用实践

    基于nginx+lua+redis高性能api应用实践 前言 比较传统的服务端程序(PHP.FAST CGI等),大多都是通过每产生一个请求,都会有一个进程与之相对应,请求处理完毕后相关进程自动释放. ...

  3. Nginx插件之openresty反向代理和日志滚动配置案例

    Nginx插件之openresty反向代理和日志滚动配置案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.openresty介绍 1>.Nginx介绍 Nginx是一款 ...

  4. 使用nginx和tomcat配置反向代理和动静分离

    背景 本人主修的编程语言是Java语言,因此最开始接触的Web开发也是JSP技术.使用Java开发的Web应用需要部署在专门的服务器程序上运行,比如Tomcat.但是一般很少会有人将Tomcat作为用 ...

  5. 通过Nginx+tomcat+redis实现反向代理 、负载均衡及session同步

    一直对于负载均衡比较陌生,今天尝试着去了解了一下,并做了一个小的实验,对于这个概念有一些认识,在此做一个简单的总结 什么是负载均衡 负载均衡,英文 名称为Load Balance,指由多台服务器以对称 ...

  6. nginx和tomcat实现反向代理、负载均衡和session共享

    这类的文章很多,nginx和tomcat实现反向代理.负载均衡实现很容易,可以参照http://blog.csdn.net/liuzhigang1237/article/details/8880752 ...

  7. Nginx的安装及反向代理设置

    因为项目的缘故,接触到了Nginx的安装和反向代理设置,和大家分享下. 一.Nginx的下载.安装cd /homewget http://nginx.org/download/nginx-1.0.5. ...

  8. nginx与apache配合反向代理技术1

    序:最近在看Dimitri Aivaliotis的<Mastering Nginx>,刚好跆拳道课下班在路上看了反向代理服务器,准备在自己的博客VPS尝试一下 web代理服务器可以实现分布 ...

  9. Nginx 负载均衡和反向代理实践

    nginx 以哪个配置文件启动 Nginx 负载均衡和反向代理实践 环境介绍 192.168.1.50    在这台主机上配置Nginx 的反向代理,负载均衡,和web1,web1使用的81号端口 1 ...

随机推荐

  1. Day2作业及默写

    1.判断下列逻辑语句的True,False. 1) 1 > 1 or 3 < 4 or 4 > 5 and 2 > 1 and 9 > 8 or 7 < 6 Fal ...

  2. eclipse 设置Java快捷键补全

    打开Eclipse,点击Window--Preferences--Java--Editor--ContentAssist Auto Activation 勾选Enable auto activatio ...

  3. 1--Selenium环境准备--Eclipse 添加Testng插件

    Eclipse安装TestNG TestNG官网地址:http://testng.org/ 1.离线安装TestNG插件: 受网络等因素影响,在线安装方式速度比较慢,可以通过如下方式离线安装TestN ...

  4. PAT 乙级 1066. 图像过滤(15)

    图像过滤是把图像中不重要的像素都染成背景色,使得重要部分被凸显出来.现给定一幅黑白图像,要求你将灰度值位于某指定区间内的所有像素颜色都用一种指定的颜色替换. 输入格式: 输入在第一行给出一幅图像的分辨 ...

  5. 【Maven】Project configuration is not up-to-date with pom.xml错误解决方法

    导入一个Maven项目之后发现有一个如下的错误: Project configuration is not up-to-date with pom.xml. Run project configura ...

  6. 序列化 json 模块

    什么是序列化? 将python中的列表,字典,元组,集合转换成字符串的过程就叫做序列化,反之叫做反序列化. 我们把变量从内存中变成可存储或传输的过程称之为序列化,序列化之后,就可以把序列化后的内容写入 ...

  7. canvas默认是黑色全透明,不是白色全透明。

  8. 【error】'isnan' was not declared in this scope

    error问题 'isnan' was not declared in this scope isnan在cmath中被取消宏定义: // These are possible macros impo ...

  9. Spring 注解详细分析解释有实例

    概述 注释配置相对于 XML 配置具有很多的优势: 它可以充分利用 Java 的反射机制获取类结构信息,这些信息可以有效减少配置的工作.如使用 JPA 注释配置 ORM 映射时,我们就不需要指定 PO ...

  10. jmeter定时器

    一.定时器的作用 1.定时器是在每个sampler(采样器)之前执行的,而不是之后(无论定时器位置在sampler之前还是下面): 2.当执行一个sampler之前时,所有当前作用域内的定时器都会被执 ...