共计 2924 个字符,预计需要花费 8 分钟才能阅读完成。
前面的文章曾提过动态修改代理,此处呢就记录下动态修改upstream,一个样例场景就是动态路由:根据一些请求特征(arg/header/cookie/ip等)将请求分流到不同upstream中
nginx动态修改proxy_pass
很久之前博主用nginx的reslover实现dns解析动态切换proxy_pass,使用该方式可以切任意一台后端,单仅仅是一台!此篇则要实现upstream后端组的切换,比如目前有两个upstream组
upstream a_upstream {
server 192.168.44.201:18081;
server 192.168.44.202:18081;
}
upstream b_upstream {
server 192.168.44.203:18081;
server 192.168.44.204:18081;
}
此时的location引流到a_upstream,如果要切流到b_upstream,那就需要更改proxy_pass指令内容并reload
location / {
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://a_upstream;
}
如果不想手动更改,则可以将proxy_pass指令值提取成变量如:proxy_pass http://$select_ups;
在原生nginx中可以用set指令配合if做条件判断实现修改a_upstream,或者用map指令映射。
location / {
if ($remoter_addr ~ ^192.168.[0-9]{1,3}.[0-9]{1,3}$){
set $select_ups b_upstream;
}
proxy_pass http://a_upstream;
}
使用openresty的lua进行动态upstream处理
简单样例
此处则使用lua来做逻辑判断并选择upstream,此时就需要用到set_by_lua*指令
location / {
set_by_lua_block $select_ups {
local iputils = require("resty.iputils")
iputils.enable_lrucache()
local internal_ips = {
"192.168.44.0/24",
}
local internal_list = iputils.parse_cidrs(internal_ips)
local res, err = iputils.ip_in_cidrs(ngx.var.remote_addr, internal_list)
if not res then
ngx.log(ngx.INFO, "ip is from internet: ", err)
return "a_upstream"
end
return "b_upstream"
}
proxy_pass http://$select_ups;
}
客户APP端自定义upstream
上面例子是根据请求特征自动分流,如果不想自动控制,想手动控制动态修改则可以修改判断逻辑,引入自定义变量进行判断:
- 使用lua_shared_dict定义一个全局(所有worker进程)共享区域内存用于存储变量
- 一个switch_ups接口,用于修改全局变量值
lua_shared_dict ups_shm 1m;
upstream a_upstream {
server 192.168.44.201:18081;
server 192.168.44.202:18081;
}
upstream b_upstream {
server 192.168.44.203:18081;
server 192.168.44.204:18081;
}
upstream c_upstream {
server 192.168.44.205:18081;
server 192.168.44.206:18081;
}
switch_ups切换upstream接口
location = /switch_ups {
access_by_lua_file lua/ip_acl.lua;
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 myups_shm = ngx.shared.ups_shm
--- 此处以remote_addr为key,从而实现为每个client设置ups
local ups_src = myups_shm:get(ngx.var.remote_addr)
ngx.say("Current upstream is :", ups_src)
ngx.log(ngx.WARN, host, " change upstream from ", ups_src, " to ", ups)
local succ, err, forcible = myups_shm:set(ngx.var.remote_addr, ups)
ngx.say(host, " change upstream from ", ups_src, " to ", ups)
}
}
代理location
location / {
set_by_lua_block $select_ups {
local ups = ngx.shared.ups_shm:get(ngx.var.remote_addr)
if ups ~= nil then
ngx.log(ngx.WARN, "get [", ups,"] from ngx.shared")
return a_upstream
end
return ups
}
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 ;
}
目前client可以根据remote_addr进行绑定upstream,从而实现自主选择upstream,若未配置,则走默认upstream
# 来自113.12.23.156的client
curl http://www.xadocker.cn/switch_ups?upstream=b_upstream
# 来自84.12.23.156的client
curl http://www.xadocker.cn/switch_ups?upstream=c_upstream
正文完