访问 VIP 缓慢的调查

将某个 https 的域名迁移到 lvs,部署完成,绑定 hosts 测试过程中发现 GET 请求非常的缓慢,一个 90KB 的图片耗费的时间长达几十秒甚至超过 1min,这个在未迁移前是从未出现过的现象。
为了一步一步调查,绑定了 hosts 直接访问 rs,结果跟未迁移前效果一样,但是直接访问 VIP 则十分的缓慢。看到这么多的现象,第一反应是难道经过了 VIP 之后 ssl 的处理速度会急剧下降?直接用浏览器自带的开发工具观察好了,发现包含 DNS 查询之前的响应还是很快的,从 Connecting 开始之后的每一步当然包括 SSL 了,其 RT 都是原先的 100 倍以上,Waiting 以及 Receiving 的时间更是长的惊人。
为了方便后续的分析,找了个简单的脚本,可以通过 curl 更方面的观察:

# cat curl-format.txt
    time_namelookup:  %{time_namelookup}\n
       time_connect:  %{time_connect}\n
    time_appconnect:  %{time_appconnect}\n
   time_pretransfer:  %{time_pretransfer}\n
      time_redirect:  %{time_redirect}\n
 time_starttransfer:  %{time_starttransfer}\n
                    ———-\n
         time_total:  %{time_total}\n

curl -w "@curl-format.txt" -o /dev/null -s http://wordpress.com/
连续几次的测试结果跟上面观察的到的一样。当时的第一反应是,虽然怎么都讲不通,经过了 VIP 之后质量还不到原来的 1%,但观察到的结果就是,这个 SSL 把个 VIP 搞的这么慢,为了确认确实是 https 的问题,又找了几个 http 的资源测试了一下,结果,奇怪的事情发生了,也极其的缓慢。
看来最初的判断是错误的,所有的走 VIP 的 GET 都变的极其缓慢了,那为什么之前比这个量大的多的 POST 没有任何异常了?最大的区别就是发送请求 body 的大小了,前者一个静态资源都是几十上百 K,而后者仅仅是返回一个 json 的纯文本。
直接抓包,最初仅仅是在客户端分别抓经过 VIP 跟不经过 VIP 的包,除了每一个 segment 的返回时间差距很大之外,其他的并无差异。后来经我们主管提醒,需要在服务器上也同时抓包,于是一个在原来的 Nginx 上抓,一个在 VIP 上抓,对比相面四张图应该就能看出原因所在了。



上面两张是不走 VIP 的情况,可以看到一个 90K 的文件经过 12 个 TCP segment 就重组了,看 length 这一栏也可以得出,平均一个 segment 都在8K 左右。



上面两张是走 VIP 的,所有的 segment 都变成了 1514(14B 的二层加上 MTU),导致的结果是分了 60 多个 segment。
看到这里立马就联想 2.6.32 ipvs 对 gro 的那个 bug: 2.6.32 – 2.6.36 的内核上在使用 ipvs 的情况下需要关闭 gro。这个我之前曾经单独写过一篇博客。只不过当年没有深入的研究下开启 gro 会有什么具体的影响,这次算是经历过了。
由于配置管理的问题,导致我们一个集群上部分网卡的 gro off 操作没有生效,这个其实是主因。
既然说到 gro/lro,那干脆把 tso, gso 的也一并实践一下。
tso, gso 在 Ubuntu 以及 RedHat 上默认是开启。
gro 在 Ubuntu 上默认关闭,在 Redhat 上默认开启。
lro 的在这两个发行版本上默认均是关闭。

可以看看我下面的两个抓包,第一张是 tso, gso 均关闭的情况

下面一张是单独开启 tso 或者 gso 的情况

现象是不是很明显。所以开启 tso/gso 对于绝大多数的应用来说还是很有必要的,能节约不少资源。

ref:

http://wiki.wireshark.org/CaptureSetup/Offloading

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

一切的工程都要从实用的角度出发,排除 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 或许能够支撑住这么大的量。
任何一个子系统子模块都可以遵循上面提到的的一些方面以及思路来完善。

使用 Google spreadsheets 画图并分析问题

之前也经常使用 Spreadsheets,但是仅仅是一些简单的数据处理外加一些简单的函数,直到我们想分析某个时段具体的 return code 情况,我突然想看看 Spreadsheets 能否直接出图。后来发现是可以的,只要以 add-ones 的形式添加一个叫 "QuickFit" 的插件就可以了。
这是除了 gnuplot 之外的另外一选择,优势是美观漂亮。
比如我们通过 zbx 拿到的 4xx、5xx 分析具体的错误类型。

通过
Spreadsheets,加入各个时段的数据,就能得到下面的图形

再进行下面的分析,看图一目了然,简单多了:-)

关于 ARP 的一些问题(arp cache, lvs arp, arp hijack)

涉及到 ARP 的问题还不少,包括之前 arp proxy 的问题。这里主要总结三个问题。

ARP 缓存(cache)
关于 Linux 上 ARP cache 的 timeout 时间,根据这篇文档的描述,并不是一个简单的 /proc/sys/net/ipv4/neigh/default/base_reachable_time_ms 开关能够决定的,这里面需要考虑很多的因素。
基本上,在 cache 的里面的 entry 有 stale/invalid/failed/reachable/delay 这几个状态:
# ip neighbor show
192.168.1.24 dev em1 lladdr 00:16:36:4e:3a:56 DELAY
192.168.1.10 dev em1 lladdr 84:2b:2b:76:86:6e REACHABLE
192.168.1.247 dev em1 lladdr 00:16:3e:06:01:20 DELAY

对于 ipv4 的路由表来说,里面有一套复杂的垃圾回收机制,总的来说,这个失效的时间通常在 5-10min 之间,并且跟随不同的 kernel 时间不完全一致,可以通过缩小 /proc/sys/net/ipv4/route/gc_timeout 的值来让 cache 里面的条目尽快的失效,但是依然无法保证。这里面涉及到不少 gc 过程,像 rhash_entries, net.ipv4.route.gc_elasticity, net.ipv4.route.max_size 以及 net.ipv4.route.gc_threshold 这类参数是需要结合起来调整的,具体的原理以及使用方法可以看这里。回答该问题的作者同时还写了一个仅仅通过 ARP 协议来侦测操作系统的 Neighbor-Cache-Fingerprint 工具,相关的原理可以看这里
说了这么多其实是想引出个我们线上遇到的一个问题,估计绝大多数的工程师一辈子都不会遇到。
正常情况下,服务器都只配有一个内网 IP,路由表也很简单,只要添加一条默认的通往 default gateway 的路由就好了,现在假设该路由表是下面这样的:
# route  -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
192.168.1.0     0.0.0.0         255.255.255.0   U     0      0        0 em1
0.0.0.0         192.168.1.24    0.0.0.0         UG    0      0        0 em1

可以看到,默认的网关指向了 192.168.1.24,现在,我们有这么一个需求,需要将绑定在 A 机器上的 192.168.1.24 这个 IP(同时也是充当的整个内网的网关机器的) 迁移到 B 机器上。最初,我们猜想的是,由于迁移了物理机器,虽然对于客户端来说,IP 没有变,但是 MAC 地址变了,因此可能需要手动的刷新下所有客户端的 ARP 表,这样才能及时的获取到正确的 MAC 地址。但是猜想毕竟是猜想,这跟我们实际测试以及最后线上碰到的情况完全不同,实际情况是什么了?在我们切换将 A 机器的 IP 下线,接着绑定到 B 机器之后,几乎是同一时刻,所有的机器就正确的识别到了更新后的 B 机器的 MAC 表。 也就是说,切换了网关之后,并不需要我们手动的干预,客户端就能「自动的」发现情况并主动更新。为什么会这样?我到目前为止并没有一个准确的结论,不过我猜想应该跟上面涉及到的几个链接有很大的关系,具体的我没有深究。

Continue reading

sar 的图形化

用了这么多小巧的监控工具,发现还是 sar 最强大,系统级别的 metric 是应有尽有,不管是实时的秒级监控还是历史数据,对分析近期(比如前一天或者前几天)出现的问题非常有帮助,这比不管是 Zabbix,Nagios 之类的「系统」要强大的多,典型的开相即用的好工具。默认是 10min 一次数据,这个不能完全满足我们的需求,目前我们有部分机器将 interval 缩小到了 1min 一次,并且将默认的 7d 的保存时间延长到了 90d。除此之外,就剩下出图了。
要是闲的蛋疼,可以使用 gnuplot 来把自己关心的所有 metric 全部画出来,但是这个比较麻烦,之前我自己用 gnuplut 玩了几天,对于 mission critical 场景不适用,有时候是等不及你把脚本一个一个写好再运行的。
后来找到了一个叫 Ksar 的工具,非常的方便,导入 sarxx 文件即可自动出图,到目前为止没有找到比他更方便更简单的方式了。唯一的不足是没有把 sar -A 列出来的所有 metric 都画出来,不过对于一般的问题,Ksar 出的图足够用了。Ksar 的启动图是不是很像 CS 中的场景。

对于昨天以及之前的数据,可以直接到 sa/sarxx 去取,但是对于只有 saxx(比如当天的数据或者由于某些原因 sarxxx 文件丢失了) 的文件,首先需要通过 sar 获得 sarxx  文件,然后需要将 12 小时制转换成 24h 制的才可以丢到 ksar 里面出图:
# LC_TIME="POSIX" sar -f sa30 -A  | tee sar30

注意LC_TIME 这个环境变量。另外,阿里在此基础上搞了个 tsar,个人不是很看好,原因见这里

 

ref:
http://honglus.blogspot.com/2011/02/graphing-sar-output.html

http://brablc.com/2011/06/06/how-to-change-sar-output-time-format-to-24/

kindle Fire & kindle PaperWhite

12 年托我司 CTO 从 US 带了台 Kindle Fire 回来。用了两年了,实话说,体验不是很好,首先太重,其次太厚,最后归结起来就是拿在手里不舒服,尽管是一个深度定制过的 Android,我用到的功能寥寥无几,主要就是看书,其他什么照片电影包括各种 app 的安装我基本没碰过。在 Fire 上看过的书应该不超过 10 本,之前也妄想在上面看看专业方面的文档,后来发现完全行不通,连基本的高亮做笔记的功能都没有。
年初公司发了台 PaperWhite,虽然价格只有 Fire 的一半不到,但是使用起来却比 Fire 好的多。当年向 @HDWei 借个 Kindle 3 体验了个把月,除了翻页比较慢,需要配备一个外置的阅读灯之外,整体感觉还觉还是蛮爽的。现在 PaperWhite 修正了以上的缺点,内置的阅读灯晚上熄灯看书非常方便,机身比 3 也轻不少。没理由不喜欢它,推荐。