废话不多说直接上代码
user nobody;
worker_processes auto;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 100000 ;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include nginx_status.conf;
}
stream {
lua_shared_dict dns_cache 1m;
init_worker_by_lua_block {
local function update_dns()
local resolver = require "resty.dns.resolver"
local r, err = resolver:new{
-- 这里使用阿里云内网dns 请合理更换
nameservers = {"100.100.2.138", {"100.100.2.136", 53}},
retrans = 5, -- 5 retransmissions on receive timeout
}
if not r then
ngx.log(ngx.ERR, "failed to instantiate the resolver: ", err)
return
end
local answers, err, tries = r:query("testcluster.redis.rds.aliyuncs.com", nil, {})
if not answers then
ngx.log(ngx.ERR, "failed to query the DNS server: ", err)
return
end
if answers.errcode then
ngx.log(ngx.ERR, "server returned error code: ", answers.errcode, ": ", answers.errstr)
return
end
for i, ans in ipairs(answers) do
if ans.address then
ngx.shared.dns_cache:set("myupstream", ans.address)
break
end
end
end
local ok, err = ngx.timer.at(0, update_dns)
if not ok then
ngx.log(ngx.ERR, "failed to create timer: ", err)
return
end
local ok2, err2 = ngx.timer.every(30, update_dns)
if not ok2 then
ngx.log(ngx.ERR, "failed to create timer: ", err2)
return
end
}
log_format basic '$remote_addr [$time_local] '
'$protocol $status $bytes_sent $bytes_received '
'$session_time';
access_log /data/logs/nginx-access.log basic buffer=32k;
log_format proxy '$remote_addr [$time_local] '
'$protocol $status $bytes_sent $bytes_received '
'$session_time "$upstream_addr" '
'"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"';
upstream linshibackend {
server 0.0.0.1:1; # just an invalid address placeholder
balancer_by_lua_block {
local balancer = require "ngx.balancer"
local upstream = ngx.shared.dns_cache:get("myupstream")
if not upstream then
ngx.log(ngx.ERR, "failed to get upstream from dns_cache")
return
end
local ok, err = balancer.set_current_peer(upstream, 19000)
if not ok then
ngx.log(ngx.ERR, "failed to set the current peer: ", err)
return
end
}
}
server {
listen 39000 so_keepalive=30m::10;
proxy_pass linshibackend;
access_log /logs/new.log proxy buffer=32k;
}
}
需要注意的几点
- lua_shared_dict 在 http 和 stream 上下文中都是独立的。也就是说,在 http 上下文中定义的 lua_shared_dict 在 stream 上下文中是不可见的,反之亦然。如果你在 stream 上下文中需要使用 dns_cache,你需要在 stream 上下文中重新定义它。所以本次我们是在stream中使用动态upstream,所以dict 初始化和 init work流程我们全部在stream 模块中执行。
- init 过程中不允许调用api阻塞初始化流程。所以dns请求过程要全部封装成函数update_dns。并使用ngx.timer.at 和 ngx.timer.every 后台执行。