張超:又拍雲系統開發高級工程師,負責又拍雲 CDN 平臺相關組件的更新及維護。Github ID: tokers,活躍於 OpenResty 社區和 Nginx 郵件列表等開源社區,專一於服務端技術的研究;曾爲 ngx_lua 貢獻源碼,在 Nginx、ngx_lua、CDN 性能優化、日誌優化方面有較爲深刻的研究。html
DNS 解析在 Nginx/OpenResty 的服務裏是不可分割的一個功能,本文主要來介紹下 Nginx 和 OpenResty 服務裏的一些不一樣的 DNS 解析方式以及它們之間的優缺點。nginx
不少時候咱們會在 Nginx 配置文件裏配置上一些域名,好比配置咱們的上游服務器。緩存
upstream example.com {
server foo.example.com;
}
複製代碼
對於這類域名,Nginx 會在配置解析階段就將其解析出來,接下來(請求處理過程)使用的都是當時解析獲得的 IP。Nginx 核心有一個函數 ngx_parse_url,負責對 url 格式進行分析,包括解析出主機名,端口號以及 URL path 等。針對 IPv4 的狀況,它會調用 ngx_parse_inet_url進行具體的解析任務,若是必要,最終它會調用到 ngx_inet_resolve_host進行域名解析,ngx_inet_resolve_host 大多狀況下會使用 getaddrinfo 進行解析,最終向 /etc/resolv.conf 下所配置的 DNS server 發起解析請求。性能優化
概括來講這個解析過程有兩個特色,一是使用了系統配置的 DNS server;二是解析過程是同步且阻塞的,所以這種解析方式僅在 Nginx 配置解析階段會被使用。另外這種解析方式的缺點就是隻解析一次,因此若是在 Nginx 運行過程當中域名解析發生了改變也是沒法感知到的,除非手動重啓 Nginx 服務。bash
Nginx 核心提供了一套供運行時使用的 DNS 解析機制,它充分契合 Nginx 的事件模型,一樣是異步非阻塞的,而且提供了緩存機制。http、stream 和 mail 模塊分別提供了配置指令(好比 http 模塊提供的 resolver),供咱們配置相關 DNS server 地址等信息。服務器
下面這個簡單的反向代理配置,就會在進行代理前解析 www.upyun.com 這個域名。網絡
location / {
set $myupstream www.upyun.com;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_pass http://${myupstream}/index.html;
}
複製代碼
注意若是直接在 proxy_pass 指令裏寫明須要代理的域名(即不使用變量的方式),那麼域名解析就會發生在配置解析階段了,即上面所講的過程。這其實也是一種實現動態 upstream 的方式。併發
這套運行時 DNS resolver 實際上是一個 DNS client 的角色,由它本身組織查詢報文併發送給目標 DNS 服務器,同時支持解析 IPv6 地址(從 1.5.8 開始),支持反向地址解析和 SRV 解析。它把對每一個域名的解析抽象爲一棵紅黑樹的節點,包括任何須要的信息。同時這棵紅黑樹也充當着緩存,查詢時會以域名做爲 key,若是對應緩存是新鮮的,即會複用緩存,而且會對解析獲得的地址順序進行必定的迴轉後再提供給上層使用。若是沒有緩存或者緩存過時,新的 DNS 請求會被構建而且發送。異步
固然,不少時候這套運行時的 DNS resolver 也不能徹底知足需求:socket
Cosocket 是 lua-nginx-module 提供的最強有力的接口(我的來看沒有之一)。它的 connect方法一樣支持傳入域名,以後會調用上面介紹的 Nginx 運行時 resolver 來解析對應域名,而後隨機挑選一個 IP 做爲本次鏈接的目標 IP 地址。因爲是使用的 Nginx 運行時 resolver ,若是 DNS resolver 沒法正常進行解析,則利用 Cosocket 構建的服務也都會受到影響。
OpenResty 官方開源的 lua-resty-dns 是利用 Cosocket 實現的一套百分百非阻塞的 DNS resolver,它僅僅充當了一個 DNS 解析器,沒有任何其餘的附加功能,包括緩存。
前面介紹過 Nginx 運行時 DNS resolver 在不少時候是有諸多的不便的,而 lua-resty-dns 則給咱們留了不少的擴展空間:
目前 OpenResty 生態圈已經有一些基於lua-resty-dns 實現的增強版實現,好比 Kong 的 lua-resty-dns-client。
總的來講,每一種 DNS 解析方式都有它適用的場景,也有它本身的不足,沒有最好的,只有最合適的。在程序設計的時候,須要找到最合適本身業務場景的方式,才能最大程度地保障服務的可用性和可靠性,避免帶來一些災難。
推薦閱讀:
我眼中的 Nginx(五):Nginx - 子請求設計之道 我眼中的 Nginx(四):是什麼讓你的 Nginx 服務退出這麼慢? 我眼中的 Nginx(三):Nginx 變量和變量插值 我眼中的 Nginx(二):HTTP/2 dynamic table size update 我眼中的 Nginx(一):Nginx 和位運算