diff options
Diffstat (limited to 'openresty-ext/src/assembly/resources/openresty/nginx/luaext/loadbalance')
4 files changed, 291 insertions, 0 deletions
diff --git a/openresty-ext/src/assembly/resources/openresty/nginx/luaext/loadbalance/balancer.lua b/openresty-ext/src/assembly/resources/openresty/nginx/luaext/loadbalance/balancer.lua new file mode 100644 index 0000000..48dc1d8 --- /dev/null +++ b/openresty-ext/src/assembly/resources/openresty/nginx/luaext/loadbalance/balancer.lua @@ -0,0 +1,50 @@ +--[[
+
+ Copyright (C) 2016 ZTE, Inc. and others. All rights reserved. (ZTE)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+--]]
+
+local b = require "ngx.balancer"
+local baseupstream = require "loadbalance.baseupstream"
+local log_util = require('lib.utils.log_util')
+local error_handler = require('lib.utils.error_handler')
+
+local log = log_util.log
+local ngx_ctx = ngx.ctx
+local servers = ngx_ctx.backservers
+local svc_key = ngx_ctx.svc_key
+local error_svc_not_found = error_handler.svc_not_found
+
+local status = b.get_last_failure()
+if status == nil then
+ --only reset the server status table of the service in the first attempt
+ baseupstream.check_and_reset_srv_status_ifneed(svc_key,servers)
+elseif status == "failed" then
+ local last_peer = ngx.ctx.last_peer
+ --mark the srv failed one time
+ baseupstream.mark_srv_failed(svc_key,last_peer)
+end
+
+local server,err = baseupstream.get_backserver(svc_key,servers)
+if server == nil then
+ ngx.log(ngx.WARN, ngx.var.request_id.." ".."No active backend server found! detail_info: key--"..svc_key.." "..(err or ""))
+ return
+end
+if baseupstream.can_retry(svc_key,servers) then
+ b.set_more_tries(1)
+end
+b.set_current_peer(server["ip"],server["port"])
+--log("upstreamserver",server["ip"]..":"..server["port"])
+ngx.ctx.last_peer = { ip=server["ip"], port=server["port"] }
\ No newline at end of file diff --git a/openresty-ext/src/assembly/resources/openresty/nginx/luaext/loadbalance/baseupstream.lua b/openresty-ext/src/assembly/resources/openresty/nginx/luaext/loadbalance/baseupstream.lua new file mode 100644 index 0000000..4af6dfa --- /dev/null +++ b/openresty-ext/src/assembly/resources/openresty/nginx/luaext/loadbalance/baseupstream.lua @@ -0,0 +1,66 @@ +--[[
+
+ Copyright (C) 2016 ZTE, Inc. and others. All rights reserved. (ZTE)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+--]]
+
+local _M = {
+ _VERSION = '1.0.0'
+}
+local policymodule = require "loadbalance.policy.roundrobin"
+local tbl_util = require('lib.utils.table_util')
+local peerwatcher = require "loadbalance.peerwatcher"
+local tbl_isempty = tbl_util.isempty
+
+function _M.get_backserver(svc_key,servers)
+ if tbl_isempty(servers) then return nil,"server list is empty" end
+
+ local servers_num = #servers
+ if not ngx.ctx.tried_num then
+ ngx.ctx.tried_num = 0
+ end
+ local server
+ if servers_num==1 then
+ ngx.ctx.tried_num = ngx.ctx.tried_num+1
+ -- return it directly if there is only one server
+ server = servers[1]
+ if peerwatcher.is_server_ok(svc_key,server) then
+ return server,""
+ else
+ return nil,"only one server but is not available"
+ end
+ end
+ for i=ngx.ctx.tried_num+1,servers_num do
+ ngx.ctx.tried_num = ngx.ctx.tried_num+1
+ server = policymodule.select_backserver(servers,svc_key)
+ if peerwatcher.is_server_ok(svc_key,server) then
+ return server,""
+ end
+ end
+ return nil,"serveral server but no one is available"
+end
+
+function _M.can_retry(svc_key,servers)
+ return ngx.ctx.tried_num < #servers
+end
+
+function _M.mark_srv_failed(svc_key, srv)
+ peerwatcher.set_srv_status(svc_key, srv, true)
+end
+
+function _M.check_and_reset_srv_status_ifneed(svc_key, servers)
+ peerwatcher.check_and_reset_srv_status_ifneed(svc_key,servers)
+end
+return _M
\ No newline at end of file diff --git a/openresty-ext/src/assembly/resources/openresty/nginx/luaext/loadbalance/peerwatcher.lua b/openresty-ext/src/assembly/resources/openresty/nginx/luaext/loadbalance/peerwatcher.lua new file mode 100644 index 0000000..6b7e522 --- /dev/null +++ b/openresty-ext/src/assembly/resources/openresty/nginx/luaext/loadbalance/peerwatcher.lua @@ -0,0 +1,107 @@ +--[[
+
+ Copyright (C) 2016 ZTE, Inc. and others. All rights reserved. (ZTE)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+--]]
+
+local _M = {
+ _VERSION = '1.0.0',
+ STATUS_OK = 0, STATUS_UNSTABLE = 1, STATUS_ERR = 2
+}
+local msbConf = require('conf.msbinit')
+local str_format = string.format
+local now = ngx.now
+local fail_timeout = msbConf.server.fail_timeout or 10
+local max_fails = msbConf.server.max_fails or 1
+
+local cluster_status = {}
+_M.cluster_status = cluster_status
+
+function _M.is_server_ok(skey, srv)
+ return _M.get_srv_status(skey, srv)==_M.STATUS_OK
+end
+
+function _M.get_srv_status(skey, srv)
+ local server_status = cluster_status[skey]
+ if not server_status then
+ return _M.STATUS_OK
+ end
+
+ local srv_key = str_format("%s:%d", srv.ip, srv.port)
+ local srv_status = server_status[srv_key]
+
+ if srv_status and srv_status.lastmodify + fail_timeout > now() then
+ return srv_status.status
+ end
+
+ return _M.STATUS_OK
+end
+
+function _M.set_srv_status(skey, srv, failed)
+ local server_status = cluster_status[skey]
+ if not server_status then
+ server_status = {}
+ cluster_status[skey] = server_status
+ end
+
+ local time_now = now()
+ local srv_key = str_format("%s:%d", srv.ip, srv.port)
+ local srv_status = server_status[srv_key]
+ if not srv_status then -- first set
+ srv_status = {
+ status = _M.STATUS_OK,
+ failed_count = 0,
+ lastmodify = time_now
+ }
+ server_status[srv_key] = srv_status
+ elseif srv_status.lastmodify + fail_timeout < time_now then -- srv_status expired
+ srv_status.status = _M.STATUS_OK
+ srv_status.failed_count = 0
+ srv_status.lastmodify = time_now
+ end
+
+ if failed then
+ srv_status.failed_count = srv_status.failed_count + 1
+ if srv_status.failed_count >= max_fails then
+ srv_status.status = _M.STATUS_ERR
+ end
+ end
+end
+
+function _M.check_and_reset_srv_status_ifneed(skey,servers)
+ local server_status = cluster_status[skey]
+ --if disabled servers of the service is empty,do nothing
+ if not server_status then
+ ngx.log(ngx.DEBUG, "service:",skey," server_status is nil")
+ return
+ end
+ local need_reset = true
+ for _, srv in ipairs(servers) do
+ local srv_key = str_format("%s:%d", srv.ip, srv.port)
+ local srv_status = server_status[srv_key]
+ if not (srv_status and srv_status.status == _M.STATUS_ERR and srv_status.lastmodify + fail_timeout > now()) then
+ --once find the server is not disabled now, no need to reset the status table. break the loop
+ ngx.log(ngx.DEBUG, "service:",skey," donot need reset,break the loop")
+ need_reset = false
+ break
+ end
+ end
+ if need_reset then
+ ngx.log(ngx.DEBUG, "service:",skey," need reset")
+ cluster_status[skey] = {}
+ end
+end
+
+return _M
\ No newline at end of file diff --git a/openresty-ext/src/assembly/resources/openresty/nginx/luaext/loadbalance/policy/roundrobin.lua b/openresty-ext/src/assembly/resources/openresty/nginx/luaext/loadbalance/policy/roundrobin.lua new file mode 100644 index 0000000..0a1b8e8 --- /dev/null +++ b/openresty-ext/src/assembly/resources/openresty/nginx/luaext/loadbalance/policy/roundrobin.lua @@ -0,0 +1,68 @@ +--[[
+
+ Copyright (C) 2016 ZTE, Inc. and others. All rights reserved. (ZTE)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+--]]
+
+local _M = {}
+_M._VERSION = '1.0.0'
+
+local tbl_util = require('lib.utils.table_util')
+local tbl_isempty = tbl_util.isempty
+local rrcache = require('lib.tools.rr_cache')
+
+function _M.select_backserver(servers,svckey)
+ local length = #servers
+ local index = ngx.ctx.last_peer_index
+
+ if index then
+ --if it is a retry request,use the index in the context as the base
+ index = index%length+1
+ else
+ --if it is a normal request,fetch index from cache as the base
+ index = rrcache.get(svckey) or 0
+ index = index%length+1
+ rrcache.set(svckey,index)
+ end
+ ngx.ctx.last_peer_index = index
+
+ --[[
+ local resty_lock = require "resty.lock"
+ local roundrobin_cache = ngx.shared.rr_cache
+
+ --step1:acquire lock
+ local opts = {["timeout"] = 0.002,["exptime"] = 0.05}--this can be set using the conf file
+ local rrlock = resty_lock:new("rr_locks",opts)
+ local elapsed, err = rrlock:lock(svckey)
+ if not elapsed then
+ --return fail("failed to acquire the lock: ", err)
+ end
+ --step2:lock successfully acquired!incr the index
+ local index, err = roundrobin_cache:get(svckey)
+ if not index then
+ index = 0
+ end
+ index = index%length+1
+
+ --step3:update the shm cache with the new index
+ roundrobin_cache:set(svckey,index)
+
+ --step4:release the lock
+ local ok, err = rrlock:unlock()
+ ]]
+ return servers[index],nil
+end
+
+return _M
\ No newline at end of file |