咱们使用 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缓存问题? - 黑板擦的回答 - 知乎