運維遇坑記錄(3)-Nginx緩存了DNS解析形成後端不通

1 問題現象

咱們使用 Nginx 的時候,常常會用到 Proxy 功能,爲了方便管理,後端站點或者服務通常用域名來表示。nginx

在運維過程當中,有一次後端須要切換,按理說,只須要更改 DNS 解析到新的 IP 就能完成切換,而後發現更改 DNS 解析後,走 Nginx 怎麼也訪問不了後端,而在 Nginx 機器上直接 curl 後端是沒有問題的。shell

問題找了半天發現是 Nginx 會緩存 DNS 解析,須要重載 Nginx 纔會刷新。後端

2 問題重現

在測試機(centos6.5)上安裝 Nginx(1.10.2),寫入測試用的 Nginx Server 配置,配置很是簡單,就是 www.test.com 轉給 proxy.test.com,最後會返回 200 OKcentos

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,就沒有問題了測試

image

3 問題探索

我也沒看過 Nginx 代碼,對於 DNS 緩存問題仍是隻能手動探索

3.1 何時緩存的

經常使用 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 解析,其餘版本尚未試。

3.2 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,能夠看到,第一次請求成功,第二次卡了一段時間後返回成功

image

查看第二次請求的日誌,發現有一個失敗的和成功的,意味着 Nginx 確實去請求了錯誤的 IP,當不通的時候就會換下一個 IP 進行請求

image

結論: Nginx 會緩存全部 DNS 解析

4 緩存問題的解決方案

4.1 每次更改 DNS 解析都重載 Nginx

重載 Nginx 必定會刷新緩存,這是最保險也是最麻煩的一種方案,若是體量小還能夠接受,若是 Nginx 實例比較多就有些困難,除非有批量運維工具幫忙。

4.2 使用 Nginx 的 resolver

咱們在使用 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緩存問題? - 黑板擦的回答 - 知乎
相關文章
相關標籤/搜索