并发连接同一地址超时问题
今天和duolong一起追查connect超时问题,结果发现是arp pending queue len的原因;
1. 现象描述
现象a:自己写的client程序,开启16个socket并发connect同一server(异步框架,超时时间为2s),结果其中3个socket连接成功,其余13个超时失败;
现象b:一次试验后,接下来多次连续试验都会成功(不出现超时现象);
现象c:停止试验一段时间后,再次试验,现象同b;
现象d:每次试验前,主动删除相应server的arp条目(arp -d server-ip),问题稳定复现;
现象e:抓包结果如下,arp请求成功后,3个socket的syn包立刻发出;13个socket的syn包,3s后才发出;
2. 原因追查
根据上述现象,查看2.6.32源码,围绕arp相关(neighbour)的代码,发现arp模块有个queue(neigh->parms->queue_len)长度默认为3,该队列用于存储arp尚未成功pengding的skb,如,我们试验中的syn包;如果因arp pending的skb超过3,则arp模块会丢弃queue中老的skb。
源码路径:neigh_resolve_output()->neigh_event_send()->__neigh_event_send()
源码片段:
if (neigh->nud_state == NUD_INCOMPLETE) {
if (skb) {
if (skb_queue_len(&neigh->arp_queue) >=
neigh->parms->queue_len) {
struct sk_buff *buff;
buff = __skb_dequeue(&neigh->arp_queue);
kfree_skb(buff);
NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);
}
__skb_queue_tail(&neigh->arp_queue, skb);
}
分析:16个并发connect的syn包,由于arp失效/重新请求,只有最后的3个保存在queue中(与上图中成功的syn包端口号最大的现象吻合),其余13个被丢弃,tcp层3s后重传13个syn包(netstat -s | grep timeout,超时重传计数增大13);另外,查看“NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards”)相关的ures_discards计数也增大13;
相关参数:neigh->parms->queue_len 可以通过/proc/sys/net/ipv4/neigh/eth0/unres_qlen调节大小;
unres_discards计数可以通过/proc/net/stat/arp_cache (unresolved_discards的值)查看(注意该计数是per cpu的);
3. 解决方法
增大arp pending queue len, echo 32 > /proc/sys/net/ipv4/neigh/eth0/unres_qlen;
4. 快速复现方法
下面提供一个简单的复现上述问题的方法;
第一步:删除相应arp cache, 命令: arp -d server-ip
第二步:发送多个数据包长度的ping,命令:ping -c 2 -s 8000 server-ip
原文链接:http://blog.sina.com.cn/u/2015038597