DevOps: 一例高负载多并发服务器连接池满的异常排解过程

今天是三八国际妇女节, 也是中国农历二月二/龙抬头的节日,恭祝女同胞节日快乐!恭祝中国善良的人们都抬头见喜!

好一阵子没更新Blog,今天也借这喜气冲刷一下往日的阴霾,经过多日的观察,终于找到这阵子“有福新闻”高负载多并发服务器的异常报错背后的原因之一。此前在Blog中频繁观测到 GWA2 PHP Memcached的报错,并且在代码层面进行了多次调优,问题暂时得到缓解,深层并未深究出个所以然。

“GWA2 PHP Memcached自动追加服务器连接?一例缓存服务被击穿的异常分析”, -R/52SP  。

在进行日常服务器状态巡检时,先是发现 Apache 在数日的持续运行中,会有 segmentation fault 导致的死掉,于是对 Apache 2.4.x 进行升级到最新版的操作,然而加了保护措施。尽管偶尔有 Apache child 有 segmentation fault退出,但整个服务顽强的活着.

后续几日的连续观测中,Apache暂无异常死掉,而 GWA2 PHP Memcached再次开始报错,报错信息为唯一的 127.0.0.1/11211 服务被标记为 DEAD (error code: 35). 然而在终端用 telnet 进行手工模拟时,memcached的服务又是正常的,这是为何?时好时坏,随机出错吗?

近日继续探测,在最近的一次服务器上尝试使用 ping ufqi.com 时,命令行开始报错说 sendmeg not permitted… 于是一例服务器操作系统层面的问题被曝露出来。

ping命令的无法执行,可能是网络配置或操作系统异常,循着这个思路,我们使用 journalctl -f 命令,很快看到 kernel层的报错信息:

Mar 08 04:43:06 srv21 kernel: nf_conntrack: nf_conntrack: table full, dropping packet
Mar 08 04:43:06 srv21 kernel: nf_conntrack: nf_conntrack: table full, dropping packet
Mar 08 04:43:06 srv21 kernel: nf_conntrack: nf_conntrack: table full, dropping packet

原来是系统的网络连接池出现了问题!关于 “nf_conntrack: table full, dropping packet” 这里 -R/u2SR 有详细的解释。 简单地说,操作系统集成了 Netfilter 防火墙服务,基于 iptables 的操作系统的连接管理器中,有四个 table(表) 和五个 chain(链)。


Fig1. Iptables 4 tables and 5 chains

Tables: categorized by different operations to data packets.

raw: highest priority, only appied to PREROUTING and OUTPUT chain. When we don’t need to do NAT, we can use RAW table to increase performance.

mangle: modify certain data packet

nat: NAT, port mapping, address mapping

filter: filter

Chains: categorized by different hooks.

PREROUTING: packet before going to route table

INPUT: after packet passing route table, destination is current machine

FORWARDING: after packet passing route table, destination is not current machine

OUTPUT: packet comes from current machine and to outside

POSTROUTIONG: packet before going to network interface

当操作系统处理 TCP/IP 连接相关模块出错时,所有基于连接的服务都会报出异常。这是此前在代码层无论如何优化都没办法解决OSI分层中更底层的问题。

操作系统默认的并发连接数为 65535, 通过命令:cat /proc/sys/net/netfilter/nf_conntrack_max  可以查看到。 如果通过命令 cat /proc/sys/net/netfilter/nf_conntrack_count 获得到的数字等于 max 的最大值时,此时再有新创建连接的需求就会报错,当创建连接失败时,基于其上的所有应用都将失败,而这些在代码层并不容易解决。推荐的 /proc/sys/net/netfilter/nf_conntrack_max 值的计算公式: CONNTRACK_MAX = RAMSIZE (in bytes) / 16384 / (ARCH / 32) , 如 8GB RAM in x86_64 OS,  max = 8*1024^3/16384/2=262144 。

当一台繁忙的服务器的连接数超过默认值时,需要通过修改 /proc/sys/net/netfilter/nf_conntrack_max  来使得系统能够接收更多连接进来。

临时修改:
echo 524288 > /proc/sys/net/netfilter/nf_conntrack_max
or
sysctl -w net.netfilter.nf_conntrack_max=262144
永久修改:
在 /etc/rc.d/after.local  或者 /etc/rc.d/rc.local 中增加上述命令行语句。

除了增加 /proc/sys/net/netfilter/nf_conntrack_max 参数设定外,还可以通过调整 iptables 的表或者链上相关规则来进行调优,更多参考: -R/u2SR 。

“有福新闻”, “全国招投标信息中心” 等服务又可以畅快地运行并有信心地迎接下一次洪峰的到来。

小结:
1. 在代码层很难发现操作系统层的问题,可行的路线是分析应用层源码;
2. 系统层的异常,通过具有随机性,比如连接数,是一个动态变化数据,可能下一秒异常就没有了,无法确定重现的问题为 troubleshooting 带来了一定的障碍。
但是,已有的问题,在没解决之前,会再次发生,这是确定的。

This entry was posted in -GWA2, 服务器运维, 计算机技术 and tagged , , , , . Bookmark the permalink.

One Response to DevOps: 一例高负载多并发服务器连接池满的异常排解过程

  1. Wadelau says:

    继续优化:
    echo 60 > /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_time_wait
    echo 60 > /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_fin_wait
    echo 300 > /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established

发表评论

电子邮件地址不会被公开。 必填项已用*标注