lua-resty-checkups
在纯 ngx_lua 中管理 Nginx 上游
$ opm get firesnow/lua-resty-checkups
名称
lua-resty-checkups - 在纯 ngx_lua 中管理 Nginx 上游
[!构建状态](https://travis-ci.org/upyun/lua-resty-checkups)
状态
在大多数情况下可能已经可以投入生产,但尚未在实际环境中得到验证。请查看问题列表,如果您有任何问题或疑问,请告诉我。
功能
定期向上游服务器发送心跳
主动和被动健康检查
动态上游更新
通过加权轮询或一致哈希进行负载均衡
与 Nginx 上游块同步
按层级或键尝试集群
概述
-- config.lua
_M = {}
_M.global = {
checkup_timer_interval = 15,
checkup_shd_sync_enable = true,
shd_config_timer_interval = 1,
}
_M.ups1 = {
cluster = {
{
servers = {
{host="127.0.0.1", port=4444, weight=10, max_fails=3, fail_timeout=10},
}
},
},
}
return _M
-- nginx.conf
lua_package_path "/path/to/lua-resty-checkups/lib/?.lua;/path/to/config.lua;;";
lua_shared_dict state 10m;
lua_shared_dict mutex 1m;
lua_shared_dict locks 1m;
lua_shared_dict config 10m;
server {
listen 12350;
return 200 12350;
}
server {
listen 12351;
return 200 12351;
}
init_worker_by_lua_block {
local config = require "config"
local checkups = require "resty.checkups.api"
checkups.prepare_checker(config)
checkups.create_checker()
}
server {
location = /12350 {
proxy_pass http://127.0.0.1:12350/;
}
location = /12351 {
proxy_pass http://127.0.0.1:12351/;
}
location = /t {
content_by_lua_block {
local checkups = require "resty.checkups.api"
local callback = function(host, port)
local res = ngx.location.capture("/" .. port)
ngx.say(res.body)
return 1
end
local ok, err
-- connect to a dead server, no upstream available
ok, err = checkups.ready_ok("ups1", callback)
if err then ngx.say(err) end
-- add server to ups1
ok, err = checkups.update_upstream("ups1", {
{
servers = {
{host="127.0.0.1", port=12350, weight=10, max_fails=3, fail_timeout=10},
}
},
})
if err then ngx.say(err) end
ngx.sleep(1)
ok, err = checkups.ready_ok("ups1", callback)
if err then ngx.say(err) end
ok, err = checkups.ready_ok("ups1", callback)
if err then ngx.say(err) end
-- add server to new upstream
ok, err = checkups.update_upstream("ups2", {
{
servers = {
{host="127.0.0.1", port=12351},
}
},
})
if err then ngx.say(err) end
ngx.sleep(1)
ok, err = checkups.ready_ok("ups2", callback)
if err then ngx.say(err) end
-- add server to ups2, reset rr state
ok, err = checkups.update_upstream("ups2", {
{
servers = {
{host="127.0.0.1", port=12350, weight=10, max_fails=3, fail_timeout=10},
{host="127.0.0.1", port=12351, weight=10, max_fails=3, fail_timeout=10},
}
},
})
if err then ngx.say(err) end
ngx.sleep(1)
ok, err = checkups.ready_ok("ups2", callback)
if err then ngx.say(err) end
ok, err = checkups.ready_ok("ups2", callback)
if err then ngx.say(err) end
}
}
}
上面定义的/t 位置的典型输出为
no servers available
12350
12350
12351
12350
12351
配置
Lua 配置
Checkups 的配置文件是一个 lua 模块,它包含两个部分:全局部分和集群部分。
下面展示了一个 checkups 的示例配置文件:
-- config.lua
-- Here is the global part
_M = {}
_M.global = {
checkup_timer_interval = 15,
checkup_timer_overtime = 60,
default_heartbeat_enable = true,
checkup_shd_sync_enable = true,
shd_config_timer_interval = 1,
}
-- The rests parts are cluster configurations
_M.redis = {
enable = true,
typ = "redis",
timeout = 2,
read_timeout = 15,
send_timeout = 15,
protected = true,
cluster = {
{ -- level 1
try = 2,
servers = {
{ host = "192.168.0.1", port = 6379, weight=10, max_fails=3, fail_timeout=10 },
{ host = "192.168.0.2", port = 6379, weight=10, max_fails=3, fail_timeout=10 },
}
},
{ -- level 2
servers = {
{ host = "192.168.0.3", port = 6379, weight=10, max_fails=3, fail_timeout=10 },
}
},
},
}
_M.api = {
enable = false,
typ = "http",
http_opts = {
query = "GET /status HTTP/1.1\r\nHost: localhost\r\n\r\n",
statuses = {
[500] = false,
[502] = false,
[503] = false,
[504] = false,
},
},
mode = "hash",
cluster = {
dc1 = {
servers = {
{ host = "192.168.1.1", port = 1234, weight=10, max_fails=3, fail_timeout=10 },
}
},
dc2 = {
servers = {
{ host = "192.168.1.2", port = 1234, weight=10, max_fails=3, fail_timeout=10 },
}
}
}
}
_M.ups_from_nginx = {
timeout = 2,
cluster = {
{ -- level 1
upstream = "api.com",
},
{ -- level 2
upstream = "api.com",
upstream_only_backup = true,
},
},
}
return _M
全局配置
checkup_timer_interval: 向后端服务器发送心跳的间隔。默认值为5。checkup_timer_overtime: 检查以使计时器键过期的间隔。在大多数情况下,您不需要更改此值。默认值为60。default_heartbeat_enable: Checkups 默认情况下是否会向服务器发送心跳。默认值为true。checkup_shd_sync_enable: 为每个工作进程创建上游同步器。如果设置为false,动态上游将无法正常工作。默认值为true。shd_config_timer_interval: 从共享内存同步上游列表的间隔。默认值等于checkup_timer_interval。ups_status_sync_enable: 如果设置为true,checkups 将从 checkups 同步上游状态到 Nginx 上游块。默认值为false。ups_status_timer_interval: 从 checkups 同步上游状态到 Nginx 上游块的间隔。
集群配置
skey:_M.xxxxx。xxxxx是此集群的skey(服务键)。enable: 启用或禁用向服务器发送心跳。默认值为true。typ: 集群类型,必须是general、redis、mysql、http之一。默认值为general。general: 通过 TCPsock:connect发送心跳。redis: 通过 redisPING发送心跳。需要lua-resty-redis模块。mysql: 通过 mysqldb:connect发送心跳。需要lua-resty-mysql模块。http: 通过 HTTP 请求发送心跳。您可以在http_opts中设置自定义的 HTTP 请求和响应代码。
timeout: 连接到上游服务器的超时时间。默认值为5。read_timeout: 从上游服务器读取数据的超时时间。默认值等于timeout。send_timeout: 向上游服务器写入数据的超时时间。默认值等于timeout。http_opts: HTTP 心跳配置。仅适用于typ="http"。query: 用于发送心跳的 HTTP 请求。statuses: 如果服务器返回的代码设置为false,则认为服务器已失败。
mode: 负载均衡模式。可以设置为hash、url_hash或ip_hash。Checkups 将根据hash_key、ngx.var.uri或ngx.var.remote_addr对服务器进行负载均衡。默认值为wrr。protected: 如果设置为true,并且集群中的所有服务器都已失败,checkups 不会将最后一个失败的服务器标记为不可用(err),而是将其标记为unstable(在下一次尝试中仍然可用)。默认值为true。cluster: 您可以根据集群优先级配置多个层级,在每个层级上,您可以配置一个servers集群。只有当先前层级中的所有服务器都被认为不可用时,checkups 才会尝试下一层级。
除了按层级尝试集群之外,您还可以配置 checkups 按键尝试集群(请参阅上面的api集群)。请记住,您还应传递额外的参数(例如opts.cluster_key={"dc1", "dc2"}或opts.cluster_key={3, 1, 2})到checkups.read_ok,以使 checkups 按dc1、dc2或level 3、level 1、level 2的顺序进行尝试。如果您没有向checkups.ready_ok传递opts.cluster_key,checkups 仍然会按层级尝试集群。对于上面的api集群,checkups 最终会返回no servers available。
try: 重试次数。默认值为服务器数量。try_timeout: 限制请求响应的时间,类似于 nginxproxy_next_upstream_timeout。servers:servers的配置列出如下:weight: 设置服务器的权重。默认值为1。max_fails: 设置在fail_timeout参数设置的持续时间内,与服务器通信失败的尝试次数。默认情况下,失败尝试次数设置为0,这将禁用尝试计数。如果typ="http",则通过http_opts.statuses定义什么被视为失败尝试,或者通过checkups.ready_ok返回nil/false。此选项仅在轮询中可用。fail_timeout: 设置在持续时间内,应发生与服务器通信的指定次数失败尝试以将服务器视为不可用,以及服务器被视为不可用的时间段。默认情况下,该参数设置为10秒。此选项仅在轮询中可用。
upstream: Nginx 上游块的名称。Checkups 将在prepare_checker中从 Nginx conf 的上游块中提取服务器。需要lua-upstream-nginx-module模块。upstream_only_backup: 如果设置为true,checkups 将仅从 Nginx 上游块中提取备份服务器。
Nginx 配置
将 lua 配置文件和 checkups 的路径添加到lua_package_path中,并创建 checkups 使用的 lua 共享字典。您应该将这些行放入 Nginx 配置文件中的http块中。
lua_package_path "/path/to/lua-resty-checkups/lib/?.lua;/path/to/config.lua;;";
lua_shared_dict state 10m;
lua_shared_dict mutex 1m;
lua_shared_dict locks 1m;
lua_shared_dict config 10m;
API
prepare_checker
语法: prepare_checker(config)
阶段: init_by_lua init_worker_by_lua
将配置从config.lua复制到 checkups,从 Nginx 上游块中提取服务器,并进行一些基本初始化。此方法可以在init阶段或init_worker阶段调用。如果您想要从 Nginx 上游块中提取服务器,则必须在init_worker阶段调用此方法。
create_checker
语法: create_checker()
阶段: init_worker_by_lua
创建心跳计时器和上游同步计时器。在所有工作进程中,只创建一个心跳计时器。强烈建议在init_worker阶段调用此方法。
ready_ok
语法: res, err = ready_ok(skey, callback, opts?)
阶段: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*
从集群skey中选择一个可用的peer,并调用callback(peer.host, peer.port, opts)。
opts表接受以下字段:
cluster_key: 按cluster_key尝试集群。Checkups 将按cluster_key的顺序尝试集群。clusters_key可以是集群的名称或集群的层级。集群示例:{"cluster_name_A", "name_B", "name_C"}。层级示例:{3, 2, 1}。hash_key: 在hash负载均衡模式中使用的键。如果未设置,将使用ngx.req.uri。try: 重试次数不超过try次。try_timeout: 限制请求响应的时间,类似于 nginxproxy_next_upstream_timeout。
如果成功,返回callback的返回值,否则返回nil和一个描述错误的字符串。
如果callback返回nil或false,checkups 将认为这是一个失败的尝试,并将使用另一个 peer 重试callback。因此,**始终记住不要在成功的回调后返回nil或false。**
select_peer
语法: peer, err = select_peer(skey)
上下文: rewrite_by_lua*, access_by_lua*, content_by_lua*, balancer_by_lua
从集群skey中选择一个可用的 peer。
返回一个包含可用 peer 的host和port的表。
如果出现错误,将返回 nil 和一个描述错误的字符串。
get_status
语法: status = get_status()
阶段: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*
以json格式返回 checkups 状态。
get_ups_timeout
语法: connect_timeout, send_timeout, read_timeout = get_ups_timeout(skey)
阶段: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*
返回集群skey的超时时间。
feedback_status
语法: ok, err = feedback_status(skey, host, port, failed)
上下文: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, balancer_by_lua.*
将集群skey中的服务器host:port标记为失败(true)或可用(false)。
如果成功,返回1,否则返回nil和一个描述错误的字符串。
update_upstream
语法: ok, err = update_upstream(skey, upstream)
阶段: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*
更新集群skey。upstream与config.lua中的cluster格式相同。
如果成功,返回true,否则返回false和一个描述错误的字符串。
delete_upstream
语法: ok, err = delete_upstream(skey)
阶段: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*
从上游列表中删除集群skey。
如果成功,返回true,否则返回false和一个描述错误的字符串。
版权和许可
该捆绑包本身是在 2-clause BSD 许可证下授权的。
版权所有 (c) 2016, UPYUN(又拍云) Inc.
此模块是在 BSD 许可证条款下授权的。
允许以源代码和二进制形式重新分发和使用,无论是否修改,前提是满足以下条件
重新分发的源代码必须保留上述版权声明、此条件列表以及以下免责声明。
二进制形式的重新分发必须在随分发提供的文档和/或其他材料中复制上述版权声明、此条件列表以及以下免责声明。
本软件由版权所有者和贡献者“按原样”提供,并且任何明示或暗示的担保,包括但不限于适销性和特定用途适用性的暗示担保,均被免除。在任何情况下,版权所有者或贡献者均不对任何直接的、间接的、偶然的、特殊的、示例性的或后果性的损害(包括但不限于替代商品或服务的采购;使用、数据或利润损失;或业务中断)负责,无论其因本软件的使用而产生,无论其是根据合同、严格责任或侵权(包括疏忽或其他原因)产生的,即使已被告知此类损害的可能性。
另请参阅
作者
firesnow
许可证
2bsd
版本
-
在纯 ngx_lua 中管理 Nginx 上游 2017-04-05 03:33:47
-
使用纯 ngx_lua 管理 Nginx 上游服务器 2017-03-22 17:31:29
-
使用纯 ngx_lua 管理 Nginx 上游服务器 2016-12-22 14:52:52