Linux TCP网络程序故障排错

February 17, 2015

Tags:Troubleshooting

问题:Kernel报错误信息Out of socket memory

分析

socket内存不足通常原因是TCP协议栈内存分配不足或有太多孤儿socket没有被系统及时回收掉。

但是,从dmesg中没有找到too many orphaned sockets的报错信息,所以,也可能不是孤儿socket导致的。但这仅仅为猜测,还需要通过逐步排查来发现问题根源。

排错过程

首先我们来检查下我们TCP协议栈内存占用情况吧,看这儿:

#cat /proc/sys/net/ipv4/tcp_mem
21180   28243   42360

简单解释下输出的三组数字的含义:

  • 最左边代表最小分配内存,低于此值系统没任何问题。
  • 中间的值被称为压力值,如果最小内存分配已经超出,那么系统会根据这个值对TCP内存做出动态调整,以应付突发情况。
  • 最右侧的值为TCP内存最大分配值,也代表设定的极限了,如果超出这个值,系统就会记录错误信息:Out of socket memory OK,接下来,我们看一下当前TCP实际的使用内存的情况:
#cat /proc/net/sockstat
sockets: used 39845
TCP: inuse 125217 orphan 65738 tw 103758 alloc 121429 mem 22016
UDP: inuse 12 mem 6
UDPLITE: inuse 0
RAW: inuse 1
FRAG: inuse 0 memory 0

通过输出项“mem 22016”,我们与tcp_mem输出比较下,显然在我们设定的压力值范围内,因此,tcp_mem相关设定就不用继续排查了,继续查是否是“孤儿”导致的问题:

#cat /proc/sys/net/ipv4/tcp_max_orphans
65536

输出的是系统当前设定的TCP孤儿数量最大值。与之前socktstat输出的“orphan 65738”对比,显然,是超出了当前设定的范围。是“孤儿”导致的问题。

结论

关于tcp_max_orphans的设定说明:
系统默认可以处理的不属于任何进程的TCP sockets的最大值,一个孤儿socket要占用64K的不可交换内存!设计初衷是为了避免系统被简单DOS(拒绝服务攻击)后无穷尽的消耗TCP内存,导致网络服务彻底瘫痪所设计的一个阈值限制。
判断此值的函数实现代码参见:net/tcp.h#L307
如果你的内存够大,也可以适当增加tcp_max_orphans的值,但这时候要注意一个原则:设置的新数值需是2或4的倍数,因为内核要x2或x4 增加问题socket的score以处罚(penalize,见代码):

#echo 262144 /proc/sys/net/ipv4/tcp_max_orphans

参考链接:
http://lartc.org/howto/lartc.kernel.obscure.html
http://www.linuxfoundation.org/collaborate/workgroups/networking/ip-sysctl

· EOF ·