resolv.conf 的超时(timeout)与重试(attempts)机制
一、背景
/etc/resolv.conf 有两个默认的值至关重要,一个是超时的 timeout,一个是重试的 attempts,默认情况下,前者是 5s 后者是 2 次。
这个估计很多工程师都不是很在意,一般情况下,使用默认的值倒没什么大问题,特殊情况我会在最后说明。
要测试,不要使用 dig, host, nslook 这类工具,因为他们并没有调用 resolver 的库,可以使用 getent 来测试。上面提到的只是一些诊断的工具,对于日常的应用来说,包括 web server、mail client、db 以及各种 app server 等等,任何使用 glibc resolver 都需要经过 resolv.conf 文件。
对于 libresolv 来说,只认 resolv.conf 的前三个 nameserver,所以写的再多也没什么意义。正常情况下,resolver 会从上至下进行解析,每个 nameserver 等待 timeout 的时间,如果一直到第三个都没结果,resolver 会重复上面的步骤 (attempts – 1) 次。
默认情况下是 5s 超时,我做了两个简单的测试,把 resolv.conf 的前三个 nameserver 全部换成不存在的 1.1.1.1, 2.2.2.2, 3.3.3.3,然后可以观察下面 strace 跟踪的结果,对于 ping 以及 getent 来说,已经算是上层的应用结果了。
strace -t getent hosts baidu.com strace ping baidu.com
对于生产有什么意义了?
对于任何的代码,不管何种形式的(HTTP 的也好,DB 的连接也罢),只要是一端对另外一端的连接,都应该加上超时重试以及异常处理的。上面其实一共涉及三个点:
这里有个有意思的脚本能检测最佳的 DNS。
最后,记得 dig, nslook 只会解析 resolv.conf 的内容,而不会解析 hosts 里面内容,所以如果想让 dig 解析 hosts 里面的内容,可以通过 dnsmasq 实现。
二、nsfailover 安装使用
安装
sudo curl -q https://raw.github.com/kvz/nsfailover/master/nsfailover.sh -o /usr/bin/nsfailover.sh && sudo chmod +x $_
配置
nsfailover通过环境变量进行配置。这里是他们的默认值:
LOG_LEVEL="6" # 7 = debug, 0 = emergency NS_1="" # Primary Nameserver (172.16.0.23 for Amazon EC2). You need to set this yourself NS_2="8.8.8.8" # Secundary Nameserver: Google NS_3="4.2.2.2" # Tertiary Nameserver: Level3 NS_ATTEMPTS="1" # https://linux.die.net/man/5/resolv.conf NS_ENABLE="no" # Set to no to disable NS_FILE="/etc/resolv.conf" # Where to write resolving conf NS_SEARCH="" # Domain to search hosts in (compute-1.internal for Amazon EC2) NS_TESTDOMAIN="google.com" # Use this to determine if NS is healthy NS_TIMEOUT="3" # https://linux.die.net/man/5/resolv.conf NS_WRITEPROTECT="no" # Use this to write-protect /etc/resolv.conf
修改NS_ENABLE=”no” 为 NS_ENABLE=”yes”
sed -i 's/NS_ENABLE="no"/NS_ENABLE="yes"/' nsfailover.sh
例子:
crontab -e * * * * * NS_1=223.6.6.6 nsfailover.sh 2>&1 |logger -t cron-nsfailover
查看/var/log/messages,如下信息
Aug 24 14:52:01 nginx01-7-21 cron-nsfailover: 2017-08-24 06:52:01 UTC [ info] Best nameserver is primary (223.6.6.6) Aug 24 14:52:01 nginx01-7-21 cron-nsfailover: 2017-08-24 06:52:01 UTC [ info] No need to change /etc/resolv.conf