feat: Add multi-target load balancing support
Fixes #47. - Added lua-resty-balancer to dependencies (Dockerfile & install.sh). - Added 'targets' field to the Host model to hold additional targets. - Updated the UI to allow inputting additional targets (IP:port). - Updated targetinfo.lua to parse the additional targets and load balance between them and the primary target using resty.balancer.round_robin.
This commit is contained in:
@@ -123,6 +123,7 @@ apt-get install -y nodejs openresty
|
||||
echo "==> Lua modules"
|
||||
luarocks install lua-resty-auto-ssl
|
||||
luarocks install luasocket
|
||||
luarocks install lua-resty-balancer
|
||||
# CIDR matcher for the per-host IP allow/deny lists (hostfeatures.lua).
|
||||
# resty.limit.req is bundled with OpenResty, so no rock is needed for it.
|
||||
luarocks install lua-resty-ipmatcher
|
||||
|
||||
@@ -62,6 +62,7 @@ function M.get(ngx, domain, targetInfo)
|
||||
|
||||
local json = require "cjson"
|
||||
local redis = require "resty.redis"
|
||||
local round_robin = require "resty.balancer.round_robin"
|
||||
|
||||
if not domain then
|
||||
return nil, 499
|
||||
@@ -95,6 +96,45 @@ function M.get(ngx, domain, targetInfo)
|
||||
return nil, 406
|
||||
end
|
||||
|
||||
-- Load balancing
|
||||
local target_list = {}
|
||||
table.insert(target_list, res["ip"] .. ":" .. tostring(res["targetPort"]))
|
||||
|
||||
if res["targets"] and res["targets"] ~= "" and res["targets"] ~= "[]" then
|
||||
local decodeOk, decodedTargets = pcall(json.decode, res["targets"])
|
||||
if decodeOk and type(decodedTargets) == "table" then
|
||||
for _, t in ipairs(decodedTargets) do
|
||||
table.insert(target_list, t)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if #target_list > 1 then
|
||||
if not M.host_balancers then M.host_balancers = {} end
|
||||
local cache_key = domain .. "_" .. (res["updated_on"] or "0")
|
||||
|
||||
if not M.host_balancers[domain] or M.host_balancers[domain].key ~= cache_key then
|
||||
local b = round_robin:new()
|
||||
local nodes = {}
|
||||
for _, t in ipairs(target_list) do
|
||||
nodes[t] = 1
|
||||
end
|
||||
b:reinit(nodes)
|
||||
M.host_balancers[domain] = { b = b, key = cache_key }
|
||||
end
|
||||
|
||||
local peer = M.host_balancers[domain].b:find()
|
||||
if peer then
|
||||
local colon = peer:find(":")
|
||||
if colon then
|
||||
res["ip"] = peer:sub(1, colon - 1)
|
||||
res["targetPort"] = peer:sub(colon + 1)
|
||||
else
|
||||
res["ip"] = peer
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
ngx.ctx.targetInfo = res
|
||||
-- Remember which host this target was resolved for, so the reuse guard at
|
||||
-- the top can tell a genuine cache hit from a coalesced request for a
|
||||
|
||||
Reference in New Issue
Block a user