今天是三八国际妇女节, 也是中国农历二月二/龙抬头的节日,恭祝女同胞节日快乐!恭祝中国善良的人们都抬头见喜!
好一阵子没更新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 toPREROUTING
andOUTPUT
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
: filterChains: 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 带来了一定的障碍。
但是,已有的问题,在没解决之前,会再次发生,这是确定的。
继续优化:
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