upstream: NGINX模块lua的上游连接负载均衡和故障转移模块
安装
如果您尚未设置RPM仓库订阅,请注册。然后您可以继续以下步骤。
CentOS/RHEL 7 或 Amazon Linux 2
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install lua-resty-upstream
CentOS/RHEL 8+、Fedora Linux、Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-upstream
要在NGINX中使用此Lua库,请确保已安装nginx-module-lua。
本文档描述了lua-resty-upstream v0.10,于2019年12月19日发布。
上游连接负载均衡和故障转移模块
概述
创建一个lua 共享字典。在init_by_lua中定义您的上游池和主机,这将被保存到共享字典中。
使用connect方法返回一个已连接的tcp socket。
或者传入一个实现了connect()和set_timeout()的resty模块(例如lua-resty-redis或lua-resty-http)。
调用process_failed_hosts来处理失败的主机,而不会阻塞当前请求。
使用resty.upstream.api在初始化或运行时修改上游配置,推荐这样做!
resty.upstream.http封装了来自@pintsized的lua-resty-http。
它允许根据HTTP状态代码以及socket连接状态进行故障转移。
lua_shared_dict my_upstream_dict 1m;
init_by_lua '
upstream_socket = require("resty.upstream.socket")
upstream_api = require("resty.upstream.api")
upstream, configured = upstream_socket:new("my_upstream_dict")
if not upstream then
error(configured)
end
api = upstream_api:new(upstream)
if not configured then -- 仅在启动时重新配置,共享内存在HUP之间持续存在
api:create_pool({id = "primary", timeout = 100})
api:set_priority("primary", 0)
api:set_method("primary", "round_robin")
api:add_host("primary", { id="a", host = "127.0.0.1", port = "80", weight = 10 })
api:add_host("primary", { id="b", host = "127.0.0.1", port = "81", weight = 10 })
api:create_pool({id = "dr"})
api:set_priority("dr", 10)
api:add_host("dr", { host = "127.0.0.1", port = "82", weight = 5 })
api:add_host("dr", { host = "127.0.0.1", port = "83", weight = 10 })
api:create_pool({id = "test", priority = 5})
api:add_host("primary", { id="c", host = "127.0.0.1", port = "82", weight = 10 })
api:add_host("primary", { id="d", host = "127.0.0.1", port = "83", weight = 10 })
end
';
init_worker_by_lua 'upstream:init_background_thread()';
server {
location / {
content_by_lua '
local sock, err = upstream:connect()
upstream:process_failed_hosts()
';
}
}
upstream.socket
new
syntax: upstream, configured = upstream_socket:new(dictionary, id?)
使用提供的字典名称返回一个新的上游对象。当在init_by_lua中调用时,如果字典已经包含配置,则返回一个额外的变量。接受一个可选的id参数,如果多个upstream.socket实例使用相同的字典,则此参数必须唯一。
init_background_thread
syntax: ok, err = upstream:init_background_thread()
初始化后台线程,应在init_worker_by_lua中调用。
connect
syntax: ok, err = upstream:connect(client?, key?)
尝试按优先顺序使用所选的负载均衡方法连接到定义池中的主机。返回一个已连接的socket和一个包含连接的host、poolid和pool的表,或者返回nil和错误消息。
当传入一个socket或resty模块时,它将在成功连接后返回相同的对象或nil。
此外,哈希方法可以接受一个可选的key来定义如何对连接进行哈希以确定主机。默认使用ngx.var.remote_addr。当池的方法是轮询时,此值将被忽略。
resty_redis = require('resty.redis')
local redis = resty_redis.new()
local key = ngx.req.get_headers()["X-Forwarded-For"]
local redis, err = upstream:connect(redis, key)
if not redis then
ngx.log(ngx.ERR, err)
ngx.status = 500
return ngx.exit(ngx.status)
end
ngx.log(ngx.info, 'Connected to ' .. err.host.host .. ':' .. err.host.port)
local ok, err = redis:get('key')
process_failed_hosts
syntax: ok, err = upstream:process_failed_hosts()
处理当前请求中的任何失败或恢复的主机。通过ngx.timer.at立即生成回调,不会阻塞当前请求。
get_pools
syntax: pools = usptream:get_pools()
返回一个包含当前池和主机配置的表。例如:
{
primary = {
up = true,
method = 'round_robin',
timeout = 100,
priority = 0,
hosts = {
web01 = {
host = "127.0.0.1",
weight = 10,
port = "80",
lastfail = 0,
failcount = 0,
up = true,
healthcheck = true
}
web02 = {
host = "127.0.0.1",
weight = 10,
port = "80",
lastfail = 0,
failcount = 0,
up = true,
healthcheck = { interval = 30, path = '/check' }
}
}
},
secondary = {
up = true,
method = 'round_robin',
timeout = 2000,
priority = 10,
hosts = {
dr01 = {
host = "10.10.10.1",
weight = 10,
port = "80",
lastfail = 0,
failcount = 0,
up = true
}
}
},
}
save_pools
syntax: ok, err = upstream:save_pools(pools)
将池的表保存到共享字典中,pools必须与get_pools返回的格式相同。
sort_pools
syntax: ok, err = upstream:sort_pools(pools)
根据提供的池表在共享字典中生成优先级顺序。
bind
syntax: ok, err = upstream:bind(event, func)
绑定一个函数,当事件发生时调用。func应期望一个包含事件数据的参数。
在成功绑定时返回true,失败时返回nil和错误消息。
local function host_down_handler(event)
ngx.log(ngx.ERR, "Host: ", event.host.host, ":", event.host.port, " in pool '", event.pool.id,'" is down!')
end
local ok, err = upstream:bind('host_down', host_down_handler)
事件:host_up
当主机状态从下线变为上线时触发。事件数据是一个包含受影响主机和池的表。
事件:host_down
当主机状态从上线变为下线时触发。事件数据是一个包含受影响主机和池的表。
upstream.api
这些函数允许您动态重新配置上游池和主机。
new
syntax: api, err = upstream_api:new(upstream)
使用提供的上游对象返回一个新的api对象。
set_method
syntax: ok, err = api:set_method(poolid, method)
为指定的池设置负载均衡方法。目前支持随机轮询和哈希方法。
create_pool
syntax: ok, err = api:create_pool(pool)
从选项表创建一个新池,pool必须至少包含一个键id,该键在当前上游对象中必须唯一。
其他有效选项包括:
method负载均衡方法timeout连接超时(毫秒)priority优先级更高的池稍后使用read_timeoutkeepalive_timeoutkeepalive_poolstatus_codes参见status_codes
此时无法定义主机。
注意:IDs由此函数转换为字符串。
默认池值:
{ method = 'round_robin', timeout = 2000, priority = 0 }
set_priority
syntax: ok, err = api:set_priority(poolid, priority)
优先级必须是数字,出错时返回nil。
add_host
syntax: ok, err = api:add_host(poolid, host)
接受一个池ID和一个选项表,host必须至少包含host。如果未指定主机ID,则将根据池中主机的数量使用数字索引。
注意:IDs由此函数转换为字符串。
默认值:
{ host = '', port = 80, weight = 0}
remove_host
syntax: ok, err = api:remove_host(poolid, host)
接受一个池id和一个要从池中移除的主机id。
down_host
syntax: ok,err = api:down_host(poolid, host)
手动将主机标记为下线,该主机将不会自动恢复。
up_host
syntax: ok,err = api:up_host(poolid, host)
手动将一台死掉的主机恢复到池中。
upstream.http
用于向上游主机发起HTTP请求的函数。
new
syntax: httpc, err = upstream_http:new(upstream, ssl_opts?)
使用提供的上游对象返回一个新的HTTP上游对象。
ssl_opts是一个可选表,用于配置SSL支持。
* ssl 设置为true以启用SSL握手,默认值为false
* ssl_verify 设置为false以禁用SSL证书验证,默认值为true
* sni_host 用作SNI主机名的字符串,默认是请求的Host头
lua
https_upstream = Upstream_HTTP:new(upstream_ssl, {
ssl = true,
ssl_verify = true,
sni_host = "foo.example.com"
})
init_background_thread
syntax: ok, err = upstream_http:init_background_thread()
初始化后台线程,应在init_worker_by_lua中调用。
如果使用upstream.http后台线程,请不要在upstream.socket中调用init_background_thread方法。
request
syntax: res, err_or_conn_info, status? = upstream_api:request(params)
接受与lua-resty-http的request方法相同的参数。
在成功请求时返回lua-resty-http对象和一个包含连接主机和池的表。
如果请求失败,则返回nil、错误和建议的HTTP状态码。
local ok, err, status = upstream_http:request({
path = "/helloworld",
headers = {
["Host"] = "example.com",
}
})
if not ok then
ngx.status = status
ngx.say(err)
ngx.exit(status)
else
local host = err.host
local pool = err.pool
end
set_keepalive
syntax: ok, err = upstream_http:set_keepalive()
将保持活动超时/池从池配置传递给lua-resty-http的set_keepalive方法。
get_reused_times
syntax: ok, err = upstream_http:get_reused_times()
传递给lua-resty-http的get_reused_times方法。
close
syntax: ok, err = upstream_http:close()
传递给lua-resty-http的close方法。
HTTP健康检查
通过将healthcheck参数添加到主机,可以启用主动的后台健康检查。
值为true将启用默认检查,即对/的GET请求。healthcheck参数也可以是一个有效的lua-resty-http的request方法的参数表。
附加几个参数:
interval设置健康检查之间的时间,以秒为单位。必须大于或等于10秒。默认值为60秒。timeout设置健康检查的连接超时。默认为池设置。read_timeout设置健康检查的读取超时。默认为池设置。status_codes一个无效响应状态码的表。默认为池设置。
后台检查的失败依据与前端请求相同,除非明确覆盖。
-- 自定义检查参数
api:add_host("primary", {
host = 123.123.123.123,
port = 80,
healthcheck = {
interval = 30, -- 每30秒检查一次
timeout = (5*1000), -- 5秒连接超时
read_timeout = (15*1000), -- 15秒读取超时
status_codes = {["5xx"] = true, ["403"] = true}, -- 5xx和403响应为失败
-- resty-http参数
path = "/check",
headers = {
["Host"] = "domain.com",
["Accept-Encoding"] = "gzip"
}
}
})
-- 默认检查参数
api:add_host("primary", {host = 123.123.123.123, port = 80, healthcheck = true})
GitHub
您可以在nginx-module-upstream的GitHub仓库中找到此模块的其他配置提示和文档。