W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
最近經(jīng)常有朋友在使用一個(gè)域名地址時(shí)發(fā)現(xiàn)無法被正確解析
比如在使用 Mysql 實(shí)例時(shí)某些云會(huì)給一個(gè)私有的域名搭配自有的 ?nameserver
?使用
local client = mysql:new()
client:connect({
host = "rdsmxxxxxx.mysql.rds.xxxx.com",
port = 3306,
database = "test",
user = "test",
password = "123456"
})
以上代碼在直接使用時(shí)往往會(huì)報(bào)一個(gè)無法解析的錯(cuò)誤。那么怎么在 ?openresty
?中使用域名呢
我們可以直接在 ?nginx
?的配置文件中使用 ?resolver
?指令直接設(shè)置使用的 ?nameserver
?地址。
官方文檔中是這么描述的
Syntax: resolver address ... [valid=time] [ipv6=on|off];
Default: —
Context: http, server, location
一個(gè)簡單的例子
resolver 8.8.8.8 114.114.114.114 valid=3600s;
不過這樣的問題在于 ?nameserver
?被寫死在配置文件中,如果使用場景比較復(fù)雜或有內(nèi)部 ?dns
?服務(wù)時(shí)維護(hù)比較麻煩。
我們的代碼常常運(yùn)行在各種云上,為了減少維護(hù)成本,我采用了動(dòng)態(tài)讀取本機(jī) ?/etc/resolv.conf
? 的方法來做。
廢話不說,讓我們一睹為快。
local pcall = pcall
local io_open = io.open
local ngx_re_gmatch = ngx.re.gmatch
local ok, new_tab = pcall(require, "table.new")
if not ok then
new_tab = function (narr, nrec) return {} end
end
local _dns_servers = new_tab(5, 0)
local _read_file_data = function(path)
local f, err = io_open(path, 'r')
if not f or err then
return nil, err
end
local data = f:read('*all')
f:close()
return data, nil
end
local _read_dns_servers_from_resolv_file = function()
local text = _read_file_data('/etc/resolv.conf')
local captures, it, err
it, err = ngx_re_gmatch(text, [[^nameserver\s+(\d+?\.\d+?\.\d+?\.\d+$)]], "jomi")
for captures, err in it do
if not err then
_dns_servers[#_dns_servers + 1] = captures[1]
end
end
end
_read_dns_servers_from_resolv_file()
通過上述代碼我們成功動(dòng)態(tài)拿到了一組 ?nameserver
?的地址,下面就可以通過 ?resty.dns.resolver
? 大殺四方了
local require = require
local ngx_re_find = ngx.re.find
local lrucache = require "resty.lrucache"
local resolver = require "resty.dns.resolver"
local cache_storage = lrucache.new(200)
local _is_addr = function(hostname)
return ngx_re_find(hostname, [[\d+?\.\d+?\.\d+?\.\d+$]], "jo")
end
local _get_addr = function(hostname)
if _is_addr(hostname) then
return hostname, hostname
end
local addr = cache_storage:get(hostname)
if addr then
return addr, hostname
end
local r, err = resolver:new({
nameservers = _dns_servers,
retrans = 5, -- 5 retransmissions on receive timeout
timeout = 2000, -- 2 sec
})
if not r then
return nil, hostname
end
local answers, err = r:query(hostname, {qtype = r.TYPE_A})
if not answers or answers.errcode then
return nil, hostname
end
for i, ans in ipairs(answers) do
if ans.address then
cache_storage:set(hostname, ans.address, 300)
return ans.address, hostname
end
end
return nil, hostname
end
ngx.say(_get_addr("www.baidu.com"))
ngx.say(_get_addr("192.168.0.1"))
我這邊把解析的結(jié)果放入了 ?lrucache
?緩存了 5 分鐘,你們同樣可以把結(jié)果放入 ?shared
?中來減少 ?worker
?查詢次數(shù)。
現(xiàn)在我們已經(jīng)實(shí)現(xiàn)了自緩存體系的 ?dns
?查詢,如果搭配 ?resty.http
? 就會(huì)達(dá)到更好的效果。
一個(gè)簡單的例子是,通過解析 ?uri
?得到 ?hostname
?、?port
?、?path
?,把 ?hostname
?扔給自緩存 ?dns
? 獲取結(jié)果
發(fā)起 ?request
?請求,?addr
?+ ?port
? connect 之,設(shè)置 ?header
?的 ?host
?為 ?hostname
?,?path
?等值來實(shí)現(xiàn) ?ip
?直接訪問等高階用法。
這里就不過多的闡述了。
local client = mysql:new()
client:connect({
host = _get_addr(conf.mysql_hostname),
port = 3306,
database = "test",
user = "test",
password = "123456"
})
還有些同學(xué)可能會(huì)在 ?hosts
?文件中自定義域名和 ?ip
?,這時(shí)候 ?resolve
?是無法正常解析的。
這個(gè)時(shí)候可以借助 ?dnsmasq
?這個(gè)服務(wù)來緩存我們的 ?dns
?結(jié)果,?hosts
?的定義可以被該服務(wù)識(shí)別。
需要在 ?nginx
?的配置文件中,設(shè)置 ?resolver
? 為 ?dnsmasq
? 服務(wù)的監(jiān)聽地址即可。
See: http://hambut.com/2016/09/09/how-to-resolve-the-domain-name-in-openresty/
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: