• Nginx缓存了DNS解析造成后端不通--代理


    文章转载自:https://segmentfault.com/a/1190000022365954

    1 问题现象

    我们使用 Nginx 的时候,经常会用到 Proxy 功能,为了方便管理,后端站点或者服务一般用域名来表示。

    在运维过程中,有一次后端需要切换,按理说,只需要更改 DNS 解析到新的 IP 就能完成切换,然后发现更改 DNS 解析后,走 Nginx 怎么也访问不了后端,而在 Nginx 机器上直接 curl 后端是没有问题的。

    问题找了半天发现是 Nginx 会缓存 DNS 解析,需要重载 Nginx 才会刷新。
    2 问题重现

    在测试机(centos6.5)上安装 Nginx(1.10.2),写入测试用的 Nginx Server 配置,配置非常简单,就是 www.test.com 转给 proxy.test.com,最后会返回 200 OK

    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 文件,改为正确的 IP

    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,就没有问题了

    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,可以看到,第一次请求成功,第二次卡了一段时间后返回成功

    查看第二次请求的日志,发现有一个失败的和成功的,意味着 Nginx 确实去请求了错误的 IP,当不通的时候就会换下一个 IP 进行请求

    结论: 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;
    }
    

    }

    4.3 使用模块nginx-upstream-dynamic-servers

    模块地址: nginx-upstream-dynamic-servers

    该模块在第一次启动的时候会进行一次解析,解析完后,在 DNS 服务器设定的 TTL 过期时间内不会再次更新,过期后会再次发起解析请求

    使用方法

    http {
    resolver 8.8.8.8;

    upstream example {
    server example.com resolve;
    }
    }

    使用这种方法的时候,DNS TTL 时间需要设置短一些。
    4.4 使用模块 ngx_upstream_jdomain

    文档对应地址: domain_resolve

    ngx_upstream_jdomain 模块是一个依赖 DNS 解析实现的 upstream 负载均衡,该模式下,允许使用域名来写 upstream 后端。该模块默认情况下,会每秒做一次 DNS 解析,使用方法如下

    http {
    resolver 8.8.8.8;
    resolver_timeout 10s;

    upstream backend {
        jdomain www.baidu.com port=80 interval=5; # 每 5 秒解析一次
    }
    server {
        listen  8080;
    
        location / {
            proxy_pass http://backend;
        }
    }
    

    }

    4.5 使用其他版本 Nginx

    Tengine Tengine 的 ngx_http_upstream_dynamic 模块可以提供动态的 DNS 解析
    NGINX Plus Plus版本提供了动态解析的语法
  • 相关阅读:
    80端口被系统占用
    一些CSS技巧
    js 字符串日期 转成 Date
    mysql: java.sql.SQLException: Incorrect string value: 'xF0x9Fx92x90</...'
    tomcat升级问题
    [转]一个商业计划书模板
    [前端]利用a标签获取url里所需的内容
    回归研发一线
    在程序中打开浏览器(方法1)
    在活动之间切换(显式Intent)
  • 原文地址:https://www.cnblogs.com/sanduzxcvbnm/p/12937809.html
Copyright © 2020-2023  润新知