咱們使用 Nginx 的時候,常常會用到 Proxy 功能,爲了方便管理,後端站點或者服務通常用域名來表示。nginx
在運維過程當中,有一次後端須要切換,按理說,只須要更改 DNS 解析到新的 IP 就能完成切換,而後發現更改 DNS 解析後,走 Nginx 怎麼也訪問不了後端,而在 Nginx 機器上直接 curl
後端是沒有問題的。shell
問題找了半天發現是 Nginx 會緩存 DNS 解析,須要重載 Nginx 纔會刷新。後端
在測試機(centos6.5)上安裝 Nginx(1.10.2),寫入測試用的 Nginx Server 配置,配置很是簡單,就是 www.test.com
轉給 proxy.test.com
,最後會返回 200 OK
centos
server { listen 80; server_name www.test.com; location / { proxy_set_header Host proxy.test.com; proxy_pass http://proxy.test.com; } } server { listen 80; server_name proxy.test.com; location / { return 200 'OK'; } }
而後在 /etc/hosts
文件下寫入本地解析,www.test.com
解析到本機,proxy.test.com
解析到一個不存在的地址緩存
127.0.0.1 www.test.com 10.10.10.114 proxy.test.com
重啓 Nginx
服務器
/usr/sbin/nginx -s reload
執行測試,手動 curl www.test.com
,訪問不存在的 IP 會被 hang 住,最後超時並打印了一條錯誤日誌運維
2020/04/14 10:10:09 [error] 21634#0: *3 upstream timed out (110: Connection timed out) while connecting to upstream, client: 127.0.0.1, server: www.test.com, request: "GET / HTTP/1.1", upstream: "http://10.10.10.114:80/", host: "www.test.com"
這個時候,咱們再調整 hosts 文件,改成正確的 IPcurl
127.0.0.1 www.test.com 127.0.0.1 proxy.test.com
而後再手動 curl www.test.com
,發現仍是被 hang 住,查看日誌,發現超時日誌裏面寫的仍是舊 IP工具
2020/04/14 10:17:30 [error] 21634#0: *5 upstream timed out (110: Connection timed out) while connecting to upstream, client: 127.0.0.1, server: www.test.com, request: "GET / HTTP/1.1", upstream: "http://10.10.10.114:80/", host: "www.test.com"
使用 /usr/sbin/nginx -s reload
命令重載 Nginx,刷新緩存,再次請求 curl www.test.com
,就沒有問題了測試
我也沒看過 Nginx 代碼,對於 DNS 緩存問題仍是隻能手動探索
經常使用 Nginx 的同窗都知道,若是 Nginx proxy_pass 裏面的域名不能解析的話,是沒法啓動 Nginx 的,我看網友說啓動的時候僅僅是檢測是否能解析,只有在第一次請求的時候纔會緩存,那麼仍是手動測試一下。
先設置爲錯誤 IP,並重啓 Nginx
[root@chengqm ~]# grep 'proxy.test.com' /etc/hosts 10.10.10.114 proxy.test.com [root@chengqm ~]# /etc/init.d/nginx restart Stopping nginx: [ OK ] Starting nginx: [ OK ]
在沒有請求前,把解析改成正確 IP
[root@chengqm ~]# sed -i 's#10.10.10.114 proxy.test.com#127.0.0.1 proxy.test.com#g' /etc/hosts [root@chengqm ~]# grep 'proxy.test.com' /etc/hosts 127.0.0.1 proxy.test.com
首次請求
[root@chengqm ~]# curl www.test.com
仍是 hang 住並打印一條日誌
2020/04/14 10:32:55 [error] 23405#0: *1 upstream timed out (110: Connection timed out) while connecting to upstream, client: 127.0.0.1, server: www.test.com, request: "GET / HTTP/1.1", upstream: "http://10.10.10.114:80/", host: "www.test.com"
結論: 在 1.10.2
版本 Nginx 中,啓動 Nginx 的時候就會緩存 DNS 解析,其餘版本尚未試。
既然 Nginx 會作 DNS 緩存,那麼使用 DNS 輪詢的狀況下,只緩存第一個解析的 IP 仍是全部,咱們來測試一下。
在本機搭建 Named
服務,並加上兩個域名的解析,其中,proxy.test.com
使用了 DNS 輪詢,一個是錯誤 IP,一個是正確IP
www IN A 127.0.0.1 proxy IN A 127.0.0.1 proxy IN A 10.10.10.114
本地 DNS 地址指向本機
[root@chengqm ~]# cat /etc/resolv.conf nameserver 127.0.0.1
重啓 Nginx
[root@chengqm ~]# /etc/init.d/nginx restart Stopping nginx: [ OK ] Starting nginx: [ OK ]
手動請求 www.test.com
,能夠看到,第一次請求成功,第二次卡了一段時間後返回成功
查看第二次請求的日誌,發現有一個失敗的和成功的,意味着 Nginx 確實去請求了錯誤的 IP,當不通的時候就會換下一個 IP 進行請求
結論: Nginx 會緩存全部 DNS 解析
重載 Nginx 必定會刷新緩存,這是最保險也是最麻煩的一種方案,若是體量小還能夠接受,若是 Nginx 實例比較多就有些困難,除非有批量運維工具幫忙。
咱們在使用 Nginx 過程當中,有時須要根據 Url 傳值動態選擇 host 進行代理轉發,這種模式下,一開始是不會去進行 DNS 解析的,只有請求的時候纔會進行 DNS 解析,而且要設置 resolver
指定 DNS 服務器 IP。
這個時候,咱們就可使用 resolver
語法來解決 DNS 緩存的問題,好比說,我在原來的 Nginx 配置裏指定 DNS IP,並設置緩存 60 秒。
server { listen 80; server_name www.test.com; resolver 127.0.0.1 valid=60s; resolver_timeout 3s; set $proxy_url "proxy.test.com"; location / { proxy_set_header Host proxy.test.com; proxy_pass http://$proxy_url; } }
暫時就只知道這兩個方案,若是有其餘方案請務必 @我,這個坑實在太大了。
參考:
nginx的dns緩存問題? - 黑板擦的回答 - 知乎