0.動態upstream的好處
openresty作者,最近也要開源(在我編寫此文章時還沒開源)他們已經使用的balancer-by-lua 特性,進展issues。能動態修改upstream,使用反向代理proxy_pass, 對後端進程或機器進行:
- 動態的負載均衡控制;
- 平滑上下線服務,升級服務;
- 高可能保證–自動踢離線服務下線;
1.先說原理
想法參考自<http://sosedoff.com/2012/06/11/dynamic-nginx-upstreams-with-lua-and-redis.html>。此文章的做法是寫進redis中,好處是能多機同時切換,不足是論詢redis太頻繁。基於openresty,使用lua的控制一個內存中的一個多進程全局變量(ngx.shard),按需地變改proxy_pass的目標upsteam。
2 直接上配置代碼
http{
lua_shared_dict _G 1m; # ngx多進程全局共享內存,保存upstream值
......
upstream default_upstream {
server unix:/var/run/app-1.sock;
server 127.0.0.0.:38888;
keepalive 24;
}
......
server{
location = /_switch_upstream {
content_by_lua '
local ups = ngx.req.get_uri_args()["upstream"]
if ups == nil then
ngx.say("usage: curl /_switch_upstream?upstream=unix:/path-to-sock-file")
return
end
local host = ngx.var.http_host
local ups_src = ngx.shared._G:get(host)
ngx.log(ngx.WARN, host, " change upstream from ", ups_src, " to ", ups)
ngx.shared._G:set(host, ups)
ngx.say(host, " change upstream from ", ups_src, " to ", ups)
';
}
location ~ (^/api/|^/p/|^/m/|^/oauthapi/) {
set_by_lua $my_upstream '
local ups = ngx.shared._G: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 ;
}
}
}
3.用法
需要切換後端upstream時,使用命令:
curl http://127.0.0.1/_switch_upstream?upstream=unix:/path-to-sock-file
可以直接換成本地socket文件,也可以是ip:port, 也可是配置中預設了別一個upstream名。