运维遇坑记录(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缓存问题? - 黑板擦的回答 - 知乎
相关文章
相关标签/搜索