Merge pull request #3341 from Shopify/canary_upstream
Add canary annotation and alternative backends for traffic shaping
This commit is contained in:
commit
17cad51e47
18 changed files with 859 additions and 23 deletions
|
|
@ -127,9 +127,57 @@ local function sync_backends()
|
|||
end
|
||||
end
|
||||
|
||||
local function route_to_alternative_balancer(balancer)
|
||||
if not balancer.alternative_backends then
|
||||
return false
|
||||
end
|
||||
|
||||
-- TODO: support traffic shaping for n > 1 alternative backends
|
||||
local alternative_balancer = balancers[balancer.alternative_backends[1]]
|
||||
|
||||
local clean_target_header = util.replace_special_char(alternative_balancer.traffic_shaping_policy.header, "-", "_")
|
||||
|
||||
local header = ngx.var["http_" .. clean_target_header]
|
||||
if header then
|
||||
if header == "always" then
|
||||
return true
|
||||
elseif header == "never" then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
local clean_target_cookie = util.replace_special_char(alternative_balancer.traffic_shaping_policy.cookie, "-", "_")
|
||||
|
||||
local cookie = ngx.var["cookie_" .. clean_target_cookie]
|
||||
if cookie then
|
||||
if cookie == "always" then
|
||||
return true
|
||||
elseif cookie == "never" then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
if math.random(100) <= alternative_balancer.traffic_shaping_policy.weight then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local function get_balancer()
|
||||
local backend_name = ngx.var.proxy_upstream_name
|
||||
return balancers[backend_name]
|
||||
|
||||
local balancer = balancers[backend_name]
|
||||
if not balancer then
|
||||
return
|
||||
end
|
||||
|
||||
if route_to_alternative_balancer(balancer) then
|
||||
local alternative_balancer = balancers[balancer.alternative_backends[1]]
|
||||
return alternative_balancer
|
||||
end
|
||||
|
||||
return balancer
|
||||
end
|
||||
|
||||
function _M.init_worker()
|
||||
|
|
|
|||
|
|
@ -6,7 +6,10 @@ local _M = balancer_resty:new({ factory = resty_chash, name = "chash" })
|
|||
|
||||
function _M.new(self, backend)
|
||||
local nodes = util.get_nodes(backend.endpoints)
|
||||
local o = { instance = self.factory:new(nodes), hash_by = backend["upstream-hash-by"] }
|
||||
local o = {
|
||||
instance = self.factory:new(nodes),
|
||||
hash_by = backend["upstream-hash-by"],
|
||||
}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
|
|
|
|||
|
|
@ -102,6 +102,9 @@ function _M.after_balance(_)
|
|||
end
|
||||
|
||||
function _M.sync(self, backend)
|
||||
self.traffic_shaping_policy = backend.trafficShapingPolicy
|
||||
self.alternative_backends = backend.alternativeBackends
|
||||
|
||||
local changed = not util.deep_compare(self.peers, backend.endpoints)
|
||||
if not changed then
|
||||
return
|
||||
|
|
@ -115,7 +118,9 @@ function _M.sync(self, backend)
|
|||
end
|
||||
|
||||
function _M.new(self, backend)
|
||||
local o = { peers = backend.endpoints }
|
||||
local o = {
|
||||
peers = backend.endpoints,
|
||||
}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@ function _M.new(self, o)
|
|||
end
|
||||
|
||||
function _M.sync(self, backend)
|
||||
self.traffic_shaping_policy = backend.trafficShapingPolicy
|
||||
self.alternative_backends = backend.alternativeBackends
|
||||
|
||||
local nodes = util.get_nodes(backend.endpoints)
|
||||
local changed = not util.deep_compare(self.instance.nodes, nodes)
|
||||
if not changed then
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@ local _M = balancer_resty:new({ factory = resty_roundrobin, name = "round_robin"
|
|||
|
||||
function _M.new(self, backend)
|
||||
local nodes = util.get_nodes(backend.endpoints)
|
||||
local o = { instance = self.factory:new(nodes) }
|
||||
local o = {
|
||||
instance = self.factory:new(nodes),
|
||||
}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
|
|
|
|||
|
|
@ -108,4 +108,10 @@ local function tablelength(T)
|
|||
end
|
||||
_M.tablelength = tablelength
|
||||
|
||||
-- replaces special character value a with value b for all occurences in a string
|
||||
local function replace_special_char(str, a, b)
|
||||
return string.gsub(str, "%" .. a, b)
|
||||
end
|
||||
_M.replace_special_char = replace_special_char
|
||||
|
||||
return _M
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue