lua-resty-resolver
用于 ngx_lua 和 LuaJIT 的缓存 DNS 解析器
$ opm get jkeys089/lua-resty-resolver
名称
lua-resty-resolver - 用于 ngx_lua 和 LuaJIT 的缓存 DNS 解析器
状态
此库仍在积极开发中,被认为已准备好投入生产。
描述
一个纯 lua DNS 解析器,支持
根据上游 TTL 值缓存 DNS 查找
直接从主服务器缓存 DNS 查找(即不按工作线程复制 DNS 查询)
支持基于 DNS 的轮循负载均衡(例如,单个域名的多个 A 记录)
通过本地工作线程缓存实现低缓存争用(即,工作线程使用随机延迟从主服务器同步,以避免争用)
可选的陈旧结果,以平滑 DNS 可用性问题
可配置的最小/最大 TTL 值
合理的安全性(例如,不允许潜在的危险结果,例如
127.0.0.1
)
动机
问:为什么要使用此库?
答:您想要动态 DNS 解析 就像他们在 Nginx Plus 中做的那样
从 nginx v1.9.x 开始,您需要商业许可证才能动态解析上游服务器名称。开源版本不支持此功能,只会解析每个域一次并将其永远缓存(即,直到 nginx 重启)。有一些 解决方法,但它们并不理想(例如,不支持 keepalive)。
此模块允许我们使用标准的开源 OpenResty 包 以及 获得动态上游名称解析的好处,而不会牺牲 keepalive 等功能。
概要
# nginx.conf:
http {
lua_package_path "/path/to/lua-resty-resolver/lib/?.lua;;";
# global dns cache (may be shared for multiple domains but for best perf use separate zone per domain)
lua_shared_dict dns_cache 1m;
# create a global master which caches DNS answers according to upstream TTL
init_by_lua_block {
local err
cdnjs_master, err = require("resolver.master"):new("dns_cache", "cdnjs.cloudflare.com", {"8.8.8.8"})
if not cdnjs_master then
error("failed to create cdnjs resolver master: " .. err)
end
}
# create a per-worker client that periodically syncs from the master cache (again, according to TTL values)
init_worker_by_lua_block {
cdnjs_master:init() -- master `init` must be called from a worker since it uses `ngx.timer.at`, it is ok to call multiple times
local err
cdnjs_client, err = cdnjs_master:client()
if not cdnjs_client then
error("failed to create cdnjs resolver client: " .. err)
end
}
# use per-worker client to lookup host address
upstream cdnjs_backend {
server 0.0.0.1; # just an invalid address as a place holder
balancer_by_lua_block {
-- note: if `lua_code_cache` is `off` then you'll need to uncomment the next line
-- local cdnjs_client = require("resolver.client"):new("dns_cache", "cdnjs.cloudflare.com")
local address, err = cdnjs_client:get(true)
if not address then
ngx.log(ngx.ERR, "failed to lookup address for cdnjs: ", err)
return ngx.exit(500)
end
local ok, err = require("ngx.balancer").set_current_peer(address, 80)
if not ok then
ngx.log(ngx.ERR, "failed to set the current peer for cdnjs: ", err)
return ngx.exit(500)
end
}
keepalive 10; # connection pool MUST come after balancer_by_lua_block
}
server {
location =/status {
content_by_lua_block {
local address, err = cdnjs_client:get()
if address then
ngx.say("OK")
else
ngx.say(err)
ngx.exit(ngx.HTTP_SERVICE_UNAVAILABLE)
end
}
}
location = /js {
proxy_pass http://cdnjs_backend/
proxy_pass_header Server;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host cdnjs.cloudflare.com;
}
}
}
主方法
要加载主库,
您需要在 ngx_lua 的 lua_package_path 指令中指定此库的路径。例如,
lua_package_path "/path/to/lua-resty-resolver/lib/?.lua;;";
。您使用
require
将库加载到本地 Lua 变量中
local resolver_master = require "resolver.master"
master new
语法:local master, err = resolver_master:new(shared_dict_key, domain, nameservers [, min_ttl, max_ttl, dns_timeout, blacklist])
创建一个新的主实例。返回实例和错误字符串。如果成功,错误字符串将为 nil
。如果失败,实例将为 nil
,错误字符串将被填充。
shared_dict_key
参数指定 ngx.shared 键,用于缓存 DNS 值。可以使用同一个共享字典来解析多个域(即,主服务器会小心不要干扰其他解析其他域的主服务器)。但是,为了获得最佳性能,建议每个域使用不同的共享字典。
domain
参数指定要解析的完全限定域名。
nameservers
参数指定要查询的名称服务器列表(请参阅 resty.dns.resolver:new 中的 nameservers
参数)。
min_ttl
参数指定缓存 DNS 查询结果的最小允许时间(以秒为单位)。默认值为 10
。
max_ttl
参数指定缓存 DNS 查询结果的最大允许时间(以秒为单位)。默认值为 3600
(1 小时)。
dns_timeout
参数确定等待 DNS 结果的最大时间(以秒为单位)。我们还使用此值来安排未来的 DNS 查询(即,比 TTL 建议的时间提前查询一点,以允许在接收结果时出现高达 dns_timeout
值的潜在延迟)。注意:这不是所有名称服务器的总超时时间。总时间计算为 dns_timeout * 5
,因为我们在 resty.dns.resolver:new 中使用默认的 retrans
值。默认值为 2
。
blacklist
参数指定被禁止的 IP 地址表,如果这些地址包含在 DNS 服务器响应中,则会被忽略。默认值为 {"127.0.0.1"}
。
主实例是线程安全的,可以安全地全局共享(通常在 init_by_lua_block 中声明为全局变量)。
master init
语法:local ok, err = master:init()
初始化主实例,并导致主服务器尽快填充缓存。返回成功指示器和错误字符串。如果成功,成功指示器将为真,错误字符串将为 nil
。如果失败,成功指示器将为假,错误字符串将被填充。
init
方法必须在支持使用 ngx.timer.at 的上下文中调用(例如,第一个可用的入口点是 init_worker_by_lua_block)。此方法是幂等的,可以安全地调用任意次数,不会产生任何影响。
master set
语法:local next_query_delay = master:set(lookup_result [, exp_offset])
缓存 DNS 查询结果。返回在下次查询之前要延迟的时间(以秒为单位)。
lookup_result
参数是一个表,包含成功的查询结果(即,每个条目都是一个包含 IPv4 address
和 ttl
秒键的表)。
exp_offset
参数是与每个记录的 TTL 一起使用的过期偏移量(用于测试)。默认值为由 ngx.now 确定的当前时间戳
此方法不应该在正常操作中使用,仅在测试时有用。
master client
语法:local client, err = master:client()
用于创建新客户端的便捷方法。与使用主实例使用的相同 shared_dict_key
和 domain
调用 resolver_client:new 完全相同。
客户端方法
要加载客户端库,
您需要在 ngx_lua 的 lua_package_path 指令中指定此库的路径。例如,
lua_package_path "/path/to/lua-resty-resolver/lib/?.lua;;";
。您使用
require
将库加载到本地 Lua 变量中
local resolver_client = require "resolver.client"
client new
语法:local client, err = resolver_client:new(shared_dict_key, domain)
创建一个新的客户端实例。返回实例和错误字符串。如果成功,错误字符串将为 nil
。如果失败,实例将为 nil
,错误字符串将被填充。
shared_dict_key
参数指定 ngx.shared 键,用于缓存 DNS 值,它应该与创建主实例时使用的值相同。
domain
参数指定要解析的完全限定域名,它应该与创建主实例时使用的值相同。
客户端实例不是线程安全的,应该只在工作线程级别共享(通常在 init_worker_by_lua_block 中声明为全局变量)。注意:当 lua_code_cache 为 off
时(例如,在开发期间),由于每个请求使用新的 lua VM 模型,因此无法使用全局的每个工作线程客户端。
client get
语法:local address, err = client:get([exp_fallback_ok])
使用简单的轮循算法检索下一个缓存地址,以选择何时有多个地址可用。返回 IPv4 地址字符串和错误字符串。如果成功,错误字符串将为 nil
。如果失败,地址将为 nil
,错误字符串将被填充。
exp_fallback_ok
参数是一个布尔值,它决定是否可以返回陈旧的值(当允许使用陈旧值时为 true
,当不允许使用陈旧值时为 false
)。陈旧值是指缓存时间超过 TTL 时长的值。如果有至少一条新鲜记录,即使 exp_fallback_ok
为 true
,也会始终返回它。默认值为 false
。
客户端将根据需要自动从主缓存同步。在正常情况下,客户端不应该出现没有新鲜记录的情况。但是,如果上游名称服务器不可用,本地缓存可能会过期,而主服务器会继续重试。客户端将始终保留至少一条陈旧记录,以便它可以继续为请求提供服务,直到上游名称服务器可用。返回错误可能比使用陈旧结果更好,这就是 exp_fallback_ok
选项默认为 false
的原因。
先决条件
这些都包含在标准的 OpenResty 包 中。
安装
建议直接使用最新的 OpenResty 包。在构建 ngx_openresty 包时,您需要通过向其 ./configure
脚本传递 --with-luajit
选项来启用 LuaJIT。
此外,您需要配置 lua_package_path 指令,将 lua-resty-resolver 源代码树的路径添加到 ngx_lua 的 Lua 模块搜索路径,如下所示
# nginx.conf
http {
lua_package_path "/path/to/lua-resty-resolver/lib/?.lua;;";
...
}
然后在 Lua 中加载库
local resolver_master = require "resolver.master"
版权和许可
此模块在 BSD 许可下授权。
版权所有 (C) 2012-2020,Thought Foundry Inc.
保留所有权利。
在满足以下条件的情况下,允许以源代码和二进制形式重新分发和使用本软件,无论是否修改:
源代码的再分发必须保留上述版权声明、本条件列表以及以下免责声明。
二进制形式的再分发必须在随分发提供的文档和/或其他材料中复制上述版权声明、本条件列表以及以下免责声明。
本软件由版权持有人和贡献者“按原样”提供,并且任何明示或暗示的保证,包括但不限于适销性和特定用途适用性的暗示保证,均予以否认。在任何情况下,版权持有人或贡献者均不对因使用本软件而产生的任何直接的、间接的、附带的、特殊的、示例性的或后果性损害(包括但不限于替代商品或服务的采购;使用、数据或利润损失;或业务中断)负责,无论其是否基于合同、严格责任或侵权(包括疏忽或其他原因),即使已告知有发生此类损害的可能性。
另请参阅
ngx_lua 模块:http://wiki.nginx.org/HttpLuaModule
作者
Jon Keys
许可证
2bsd
依赖项
openresty/lua-resty-dns >= 0.21, luajit >= 2.0.0
版本
-
用于 ngx_lua 和 LuaJIT 的缓存 DNS 解析器 2020-05-13 20:08:18
-
用于 ngx_lua 和 LuaJIT 的缓存 DNS 解析器 2020-02-03 14:25:26
-
用于 ngx_lua 和 LuaJIT 的缓存 DNS 解析器 2019-07-11 16:51:49
-
ngx_lua 和 LuaJIT 的缓存 DNS 解析器 2018-01-04 17:59:47
-
ngx_lua 和 LuaJIT 的缓存 DNS 解析器 2017-06-27 23:10:45