NGINX 结合 lua 动态修改upstream

具体思路是: 

1 > 利用lua中 "lua_shared_dict" 指令开辟一个共享内存空间;

2> 通过API动态根据key值&参数修改 upstream  (这里使用 host 作为key);

3> 利用 proxy_pass 可使用变量特性及lua指令 "set_by_lua" 动态修改当前 upstream 变量即可;


以下是利用 qq.com 作为示例:

http {
	lua_shared_dict _ups_zone 64m; # 定义upstream共享内存空间
	...
	upstream qq_backend{
		server 14.17.42.40;
		server 14.17.32.211;
		server 59.37.96.63;
	}

	server {
		listen       80;
		server_name  www.qq.com *.qq.com;
		access_log  off;

		# 更新 upstream 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;
		}
	}
}

测试:

cur -x 127.0.0.1:80 www.qq.com  # 使用默认upstream
# 修改为140.206.160.207 & 61.135.157.156
curl -x 127.0.0.1:80 www.qq.com/ups_update?ups=140.206.160.207
curl -x 127.0.0.1:80 www.qq.com/ups_update?ups=61.135.157.156

这里只是一个简单的思路,并未考虑到 upstream 持久化,如需要可参考以下这篇文章, 使用 redis 来实现:

Dynamic nginx upstreams with Lua and Redis 


Lua-Resty-Checkups是一个基于luaupstream管理和健康检查模块,由又拍云开源。特点:支持周期性upstream服务管理操作支持管理和健康检查支持upstream动态更新有利于加权轮询或哈希平衡支持 Nginx C upstream同步操作可使用级别和键值实现集群使用简介:-- config.lua _M = {} _M.global = {     checkup_timer_interval = 15,     checkup_shd_sync_enable = true,     shd_config_timer_interval = 1, } _M.ups1 = {     cluster = {         {             servers = {                 {host="127.0.0.1", port=4444, weight=10, max_fails=3, fail_timeout=10},             }         },     }, }lua_package_path "/path/to/lua-resty-checkups/lib/checkups/?.lua;/path/to/config.lua;;"; lua_shared_dict state 10m; lua_shared_dict mutex 1m; lua_shared_dict locks 1m; lua_shared_dict config 10m; server {     listen 12350;     return 200 12350; } server {     listen 12351;     return 200 12351; } init_worker_by_lua_block {     local config = require "config"     local checkups = require "resty.checkups.api"     checkups.prepare_checker(config)     checkups.create_checker() } server {     location = /12350 {         proxy_pass http://127.0.0.1:12350/;     }     location = /12351 {         proxy_pass http://127.0.0.1:12351/;     }     location = /t {         content_by_lua_block {             local checkups = require "resty.checkups.api"             local callback = function(host, port)                 local res = ngx.location.capture("/" .. port)                 ngx.say(res.body)                 return 1             end             local ok, err             -- connect to a dead server, no upstream available             ok, err = checkups.ready_ok("ups1", callback)             if err then ngx.say(err) end             -- add server to ups1             ok, err = checkups.update_upstream("ups1", {                     {                         servers = {                             {host="127.0.0.1", port=12350, weight=10, max_fails=3, fail_timeout=10},                         }                     },                 })             if err then ngx.say(err) end             ngx.sleep(1)             ok, err = checkups.ready_ok("ups1", callback)             if err then ngx.say(err) end             ok, err = checkups.ready_ok("ups1", callback)             if err then ngx.say(err) end             -- add server to new upstream             ok, err = checkups.update_upstream("ups2", {                     {                         servers = {                             {host="127.0.0.1", port=12351},                         }                     },                 })             if err then ngx.say(err) end             ngx.sleep(1)             ok, err = checkups.ready_ok("ups2", callback)             if err then ngx.say(err) end             -- add server to ups2, reset rr state             ok, err = checkups.update_upstream("ups2", {                     {                         servers = {                             {host="127.0.0.1", port=12350, weight=10, max_fails=3, fail_timeout=10},                             {host="127.0.0.1", port=12351, weight=10, max_fails=3, fail_timeout=10},                         }                     },                 })             if err then ngx.say(err) end             ngx.sleep(1)             ok, err = checkups.ready_ok("ups2", callback)             if err then ngx.say(err) end             ok, err = checkups.ready_ok("ups2", callback)             if err then ngx.say(err) end     } }Lua 配置示例:_M = {} -- Here is the global part _M.global = {     checkup_timer_interval = 15,     checkup_timer_overtime = 60,     default_heartbeat_enable = true,     checkup_shd_sync_enable = true,     shd_config_timer_interval = 1, } -- The rests parts are cluster configurations _M.redis = {     enable = true,     typ = "redis",     timeout = 2,     read_timeout = 15,     send_timeout = 15,     protected = true,     cluster = {         {   -- level 1             try = 2,             servers = {                 { host = "192.168.0.1", port = 6379, weight=10, max_fails=3, fail_timeout=10 },                 { host = "192.168.0.2", port = 6379, weight=10, max_fails=3, fail_timeout=10 },             }         },         {   -- level 2             servers = {                 { host = "192.168.0.3", port = 6379, weight=10, max_fails=3, fail_timeout=10 },             }         },     }, } _M.api = {     enable = false,     typ = "http",     http_opts = {         query = "GET /status HTTP/1.1\r\nHost: localhost\r\n\r\n",         statuses = {             [500] = false,             [502] = false,             [503] = false,             [504] = false,         },     },     mode = "hash",     cluster = {         dc1 = {             servers = {                 { host = "192.168.1.1", port = 1234, weight=10, max_fails=3, fail_timeout=10 },             }         },         dc2 = {             servers = {                 { host = "192.168.1.2", port = 1234, weight=10, max_fails=3, fail_timeout=10 },             }         }     } } _M.ups_from_nginx = {     timeout = 2,     cluster = {         {   -- level 1             upstream = "api.com",         },         {   -- level 2             upstream = "api.com",             upstream_only_backup = true,         },     }, } return _M
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值