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) 次。

为了真正理解,例如下面这个场景:
search test.example.com example.com  
nameserver 192.168.0.1  
nameserver 192.168.0.2

假设 192.168.0.1 不返回结果(可能根本就不是台 DNS),我们假设需要解析 "www.devel",而这个仅仅在 www.devel.example.com 里面有记录,下面是整个执行的步骤:
1. "www.devel" on 192.168.0.1, wait until timeout (default 5 secs)
2. "www.devel" on 192.168.0.2, get reply: no such hostname
3. "www.devel" on 192.168.0.1, wait until timeout (default 5 secs)
4. "www.devel" on 192.168.0.2, get reply: no such hostname
5. "www.devel.test.example.com" on 192.168.0.1, wait until timeout (default 5 secs)
6. "www.devel.test.example.com" on 192.168.0.2, reply no such hostname
7. "www.devel.test.example.com" on 192.168.0.1, wait until timeout (default 5 secs)
8. "www.devel.test.example.com" on 192.168.0.2, reply no such hostname
9. "www.devel.example.com" on 192.168.0.1, wait until timeout (default 5 secs)
10. "www.devel.example.com" on 192.168.0.2, reply with IP address

默认情况下是 5s 超时,我做了两个简单的测试,把 resolv.conf 的前三个 nameserver 全部换成不存在的 1.1.1.1, 2.2.2.2, 3.3.3.3,然后可以观察下面 strace 跟踪的结果,对于 ping 以及 getent 来说,已经算是上层的应用结果了。
1. strace -t getent hosts baidu.com
2. strace ping baidu.com

把 timeout 设置为 1s 的结果可以看下面这个测试结果:
strace -t ping baidu.com(options timeout:1)

对于生产有什么意义了?
对于任何的代码,不管何种形式的(HTTP 的也好,DB 的连接也罢),只要是一端对另外一端的连接,都应该加上超时重试以及异常处理的。上面其实一共涉及三个点:
1. 超时,目前绝大多数的 API 都支持这类参数,包括我们线上用的 grequestsMySQLdb 等等
2. 重试,对于代码层面同样重要,跟上面类似
3. 异常处理,好的代码对于无法连接或者连接超时等问题应该及时的抛出异常打 log,而不是什么都没有,否则会加大问题定位的工作量,后期维护起来也会异常的麻烦。

这里有个有意思的脚本能检测最佳的 DNS。

最后,记得 dig, nslook 只会解析 resolv.conf 的内容,而不会解析 hosts 里面内容,所以如果想让 dig 解析 hosts 里面的内容,可以通过 dnsmasq 实现。

ref:
https://access.redhat.com/solutions/21420
http://serverfault.com/questions/562079/adjusting-how-long-linux-takes-to-fail-over-to-backup-dns-server-listed-in-resol

如何部署一个稳定高效可扩展的前端

一切的工程都要从实用的角度出发,排除 GLSB 在外,目前主流的开放的前端无非就那几种:
1. 最简单的就是 DNS RR,上手很快,缺点也很明显
2. web server + keepalived,相对智能些,依然有缺点,没有 health checker
3. 目前主流的方案 LVS(ipvs) + keepalived + web server(Nginx/Tengine),如果规模比较大,可能还会涉及到 OSPF

前端的地位不言而喻,出问题大家都只能大眼瞪小眼,保证稳定是其首要目标。这里总结一些我们线上的通用问题(前期的 benchmark 就不说了),其基本原理不仅仅适用于前端,中间件、DB 同样适用,举一反三非常重要。

Tengine
在调研比较了 Tengine, Nginx 之后,我们还是决定使用 Tengine,主要原因之一是其添加了一些非常诱人的功能,再加上我们后面有大量的技术支持,所以不是很需要担心 Tengine 本身的问题。后来偶然发现,@chobits 同学在全职开发 Tengine,就更不要担心了,全程也拉他帮我们 debug 了不少问题,提供了不少非常实用的建议,再次感谢。
1. 其支持的 reqstat 模块可以实时的针对不同的 location、server 统计到当前的 return code,这个对于整个 web server 的监控是最重要的一环。
2. 其次,对 log 部分做了改进,支持 syslog/rsyslog,这样可以直接打到后端,方便后续的归档分析。
3. upstream 几个对应的模块可以更好的检测后端机器的健康状况,不过我们没实用这个 module,而是自己编译的 fair module。
4. 另外,还支持一致性 hash、session sticky 以及灰度发布类似 tcpcopy(不推荐使用)/gor(推荐使用) 的 httpcopy 等特性,总的来说,确实比较实用。

LVS/keepalived
这个没什么特别要说的,首先是模式的选择了,目前主流就是 NAT/FNAT,DR,前者更安全,后者在出现某些问题的是时候切换 DNS 比较方便。有点要特别强调的是,keepalived 的 syntax 问题,默认没有任何的检查,我们之前少写了一个配对的括号竟然也能起起来,不禁让人感叹一下,后来找到了一个叫 keepalived-check 的工具,小巧方便,真应该直接编译到 keepalived 里面。除此之外,还有针对 vim  syntax 高亮插件。

debug
该开 debug 的初期最好开起 debug,这样能发现很多的问题。
keepalived,最主要就是看 messages 文件
tegine,把 debug 的 module 编译进去就可以看到更详细的信息了,包括一些非常重要的系统调用,recv() 在哪里出问题等等,我们通过此信息发现了不少的 upstream 问题;其次就是 log format 的定义,尽量定义的详细些,同样的能发现不少问题,多看看 error log 以及 access log,通过实时的 reqstat 就能一步一步的细化。

网络
直接上的万兆,涉及的方面还比较多,可以看我之写的一系列文档,概括一下包含下面的一些内容:
1. 路由的添加,/etc/sysconfig/network-scripts/route-INTERFACE,别在 rc.local 里面加了,太土鳖了
2. 中断的绑定,万兆的都是多队列,这个不做其他的没任何意义
3. ring buffer 调整,GRO 关闭等等
4. kernel 方面的,下面会提到

版本&打包
1. 自己编译,添加一些需要的 module,比如 fair,记得开启 –debug 模式
2. 实用 SysV 来管理进程,统一由 /etc/ini.d/ 下面的脚本来管理

内核
肯定是要重新编译的(CONFIG_IP_VS_TAB_BITS=20),下面包含一些基本的 TCP 优化
1. rmem_max/wmem_max
2. rmem_default/wmem_default
3. tcp_rmem/tcp_wmem/tcp_mem
4. netdev_max_backlpg
5. somaxconn/nginx backlog
6. timestamp/tcp_reuse/tcp_recycle

监控到位
zabbix 的 item,要么通过 trigger 来体现,要么通过 graph 来体现,如果存在于第三者,就没有存在的必要了,很少会到 "Latest data" 里面去挖来挖去,你自己的写的说不定都会忘记。
1. 系统层面的不细说,但是像 DNS resolver, NTP, fork rate, CPU freq(BIOS), 10000M 速率双工, ethtool -S 下面的一些 discard/dropped 很可能会忽略掉,这些 item 其实是非常重要的,关键的时候能派上大用途
2. 基本的 ping、curl 监控,为了确保 LVS 到 RS 的基本连通行,ping、curl 必不可少,这个在出问题的时候能第一时间确定是否是小范围或者大面积的网络故障
3. LVS 相关的,包括进程,链接情况(ipvsadm),rs 的情况等等,这个通过 zbx LLD 还是很方便的
4. Nginx 基本的 req, conn,以及 return code,rt 等等,不少都是直接从 Tengine 获取到的
5. proc 下面的 fd, open file, proc,Nginx 的比较诡异,目前已经遇到至少三次 open file 由系统值变为 1024 的,这方面监控必不可少
6. 全国各地的请求监控,这个一般是第三方的服务来帮助发现问题了

log 处理
1. 目前是本地 logrotate 一份,关闭了 compress,避免短时间内 IO 过高 LVS 以为 RS 出问题了
2. 通过 syslog 远端到另外一台机器上做压缩存档
3. 除此之外,Tengine 可以抽样获取 log,这样对服务器的压力可以大大减小

整个过程就是不断发现问题,解决问题的过程,及时的记录 post-mortem,及时的 review 当前完成的状况,这样整个系统才会朝更好的方向发展。之前发现有同学写完 post-mortem 就扔在一边不管了,虽然写了改进措施,但是由于没有及时的更进,导致的没有真正的完成需要改进的工作,结果是相同的问题继续出现,这就失去了本身的意义了。题目的「稳定高效」全篇都在提。可扩展如果是 10G 或者 20G 以下,可以通过加 RS 的方式完成,当然在这之前需要确定前端网卡能否以 wire rate 抗过 10G 或者 20G 甚至 40G(bonding) 的量,尤其全是小包的极端情况。当然,一般这么大的量已经很少只通过一个出口完成了,一般 OSPF 结合多 uplink 或许能够支撑住这么大的量。
任何一个子系统子模块都可以遵循上面提到的的一些方面以及思路来完善。

NX-OS(N7K) 也能跑崩(Nexus 7000 Stuck Sending TCNs Every 2 Seconds)

题目有点夸张,但是确实对我们的生产环境造成了很大的影响,越是基础的部件出现问题造成的损失越大。这个是触发该 bug 的两个时间段内,一台前端机器到部分后端机器的丢包情况监控。

这个 bug 跟我两年前碰到的 2.6.32 内核的 208.5 bug(1, 2) 倒是很像,弄不好又是哪个无证码农犯了除以 0 了。

发现这个 unicast flooding 的特征还是蛮明显的,比如 iftop 发现竟然出现了其他主机之间交互的流量,tcpdump 抓包也能观察到类似的现象,除了一些 ARP、HSRP 的请求回应之外不应该有大量的其他的包了。这篇文档总结了出现了该情况的几种可能。

总的来说,NX-OS 虽然已经上市好几年了,但还是不够成熟,无意中还发现可能存在 kernel panic 的风险。考虑到可能有人因为权限的问题无法打开上面的链接,我这里附一份完整的存档:

Nexus 7000 Stuck Sending TCNs Every 2 Seconds
CSCuo80937

Symptom:
If there is any TC after upgrade to 6.2.(6), 6.2.(6a) or 6.2.(8), then after
approximately 90 days of active supervisor uptime, STP TC BPDUs are sent out
every 2 seconds for a long period of time.

Conditions:
Nexus 7000 or 7700 running 6.2(6), 6.2.(6a), or 6.2(8).

Workaround:
In order to circumvent this issue until an upgrade to fixed code can be
performed,
execute the appropriate workaround depending on whether you have a
dual-supervisor or single-supervisor
configuration before each 90 days of Active supervisor uptime.

For dual-supervisor setups:
1. Reload the standby supervisor using cli "reload module x" where x is
standby supervisor slot number.
2. Use the 'show module' command to confirm that the standby supervisor is up
and in the ha-standby mode.
3. Use the system 'switchover command' to switch to the standby supervisor.

For single-supervisor setups:
1. Upgrade to 6.2.6b or 6.2.8a, depending on your business requirements.
2. Reload the switch.

Further Problem Description:
Active Supervisor Uptime can be found from "show system uptime":
N7K-7009-3# show system uptime
System start time: Fri Oct 25 09:40:58 2013
System uptime: 236 days, 8 hours, 56 minutes, 59 seconds
Kernel uptime: 110 days, 23 hours, 7 minutes, 49 seconds
Active supervisor uptime: 110 days, 23 hours, 2 minutes, 23 seconds <<<<<<<<<<<

startup 的安全问题

安全这个问题好像离绝大多数的 startup 比较遥远,好像谈到安全只有 BAT 这类规模的才会重视。
绝大多数的 startup 起家都是短糙快,怎么好搞怎么搞,怎么方便怎么搞,怎么省事怎么搞。再加上「绝大多数的创业公司都喜欢宣称自己是「平均年龄25 的年轻团队。」,正面理解起来是有活力的团队,反面理解起来,其实代表的是「招不到人,只能忽悠年轻人,组建的一只没经验靠人力时间堆砌的弱逼团队」」,其整体的安全性可想而知。
这或许在初期并没有什么问题,因为本来知道你的人就不多嘛,cracker 们也没兴趣花时间在只有几千几百用户的上团体上。
但是如果你很幸运,成为了那百分之几甚至千分之几的存活下来的,那就是另外一回事了,你们的产品会在短期内被很多的用户知道,得到了不少用户的认可,用户数量逐渐变多,接下来可能要经过一段爆发性的增长,一方面来说是好事,但是,另外一方面,对公司整体的技术也是一个非常大的挑战,再加上很多都是没什么经验的工程师,真的就是摸着石头过河了,在这期间,会经历若干次的宕机服务不可用事故,为了尽快的 available,不得不牺牲很多方面,正所谓 tradeoff,比如牺牲了安全。
然后名气慢慢大了,积累的用户数量在圈子里面也数一数二了,白帽子也好黑帽子也罢,都对其产生了很大的兴趣,随便扫扫,就发现了不少有价值的信息,至于什么信息大家自己补脑吧。
好在有类似 wooyun 这样的平台,突然有一天 startup 在 wooyun 上收到了一封「弱口令」(关于弱密码的危害,请看这里)的漏洞提交,至此,公司开始对安全有了一定的认识,发现原来弱口令还是导致直接渗透到内网,于是上上下下一顿整改,但这毕竟只是冰山一角,前几年为了方便留下的祸患太多了,接下来,不停的收到若口令、权限绕过、设计缺陷等等各种各样的漏洞报告。虽然大多数人都很重视这类问题,积极的配合整改,但总会有那么些人不以为然,认为这些事情不值一提,根据 2/8 原则,80% 的漏洞都是由 20% 的人造成的,直到某一天,发现公司的用户信息、代码被拖库了,傻眼了。
上面可能是很多 startup 都要经历的过程:为了方便随便上线,携带敏感信息的配置文件不加任何处理,无任何限制的开放对内服务的访问权限,弱密码,以上还仅仅是技术层面的因素,如果遇到叼炸天的工程师自以为是等人为非技术因素,后期需要改进沟通的更是难上加难。
出几次事故也未必是坏事,最起码让我们明白,不好好对待这个问题,迟早是要出大事的,用户信息泄漏了导致公司陷入危机的不在少数,那些处在风华正茂认为老子(或许有老娘这么一说)天下第一无人能敌写代码如行云流水天马行空 bug free 的也是会出些非常低级的错误的。很多东西,尤其是安全,仅仅是从技术层面加以控制是完全不够的,更多的是需要从行政手段上加以干预,有奖有惩,才能从根源控制。当然,上面说的这些尤其是最后一点在一个仅仅发展了两三年,连基本的工程师制度惩处措施都没有,没有强大的执行力或者说是重视此问题的有话语权工程师的干预下,是不可能做到的。