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

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

  • 老王

    为何不推荐使用tcpcopy?

    • http://jaseywang.me/ Jasey Wang

      我会在下一篇博客单独说明这个问题。

    • http://jaseywang.me/ Jasey Wang