有熟悉 TCP4 次挥手的么?请教一个昨天遇到的问题

2018-12-18 09:51:20 +08:00
 a663

当时忙是旁边小哥遇到处理的,但是最后问题原理 他也没说不明白 问题情形: 一个应用要使用 3006 端口,发现端口已被占用,使用 netstat -atnlp |grep 3006,发现一直 3006 端口的 TIME_WAITE。 是 4 次挥手时,Client 端等待 2ML 时间的等待。 原来是这里的某些服务需要连接另外一台 Redis 服务器,这边 Client 端打开打端口恰好打开了 3006,然后 netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'一查,TIME_WAITE 有 3 万多个,而且持续观察 2 个小时内 3006 端口一直是 TIME_WAITE

处理:旁边小哥先是调了内核参数 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_syncookies = 1 都不行之后,加了一个限制 TIME_WAITE 的参数 net.ipv4.tcp_max_tw_buckets = 1024 ###原默认值很大,具体忘了 ###这里 TIME_WAITE 多于该数值,会被抛弃

我的猜测是,服务器 Client 端这边有大量请求需要主动连接 redis,3006 端口刚 TIME_WAITE 结束又进入新的 TIME_WAITE,而不是“一直” TIME_WAITE

问题: 1.上面描述的这种情形的原理是什么? 2.处理方法( net.ipv4.tcp_max_tw_buckets = 1024 )会有什么坑留下?

4210 次点击
所在节点    程序员
22 条回复
90928yao
2018-12-18 10:03:58 +08:00
兄弟 出现 time wait,close wait 一般都是自己代码写得有问题 不是内核参数问题
EchoUtopia
2018-12-18 10:08:03 +08:00
用连接池吧
a663
2018-12-18 10:11:35 +08:00
@90928yao 我是运维😂😂😂😂
a663
2018-12-18 10:11:50 +08:00
@EchoUtopia 代码里面的连接池么?
liuxu
2018-12-18 10:13:43 +08:00
@90928yao 不是吧老哥,这 2 个状态是 TCP 必有的,TIME_WAITE 是为了防止 2 个 tcp 连接重传串包
liuxu
2018-12-18 10:18:46 +08:00
快速释放 time_wait 设置这 2 个参数:

net.ipv4.tcp_timestamps=1
net.ipv4.tcp_tw_recycle=1
meik2333
2018-12-18 10:18:48 +08:00
坑的话就是如果正好有阻塞的包在连接结束后又发送到了的话,可能会发生混乱。

网络环境越好出现概率越低,要同时满足:主动关闭一端已经结束、有包被阻塞在途中且最后成功被送达、正好有同样端口的新连接这几个条件,才会出现混乱。
a663
2018-12-18 10:28:37 +08:00
@liuxu 关闭本机的 timestamps 是为了避免 recycle NAT 后的坑吧?但是这样子不会对本机带来什么坑么?
a663
2018-12-18 10:31:16 +08:00
@liuxu 记错了 这样子操作,主机 NAT 在后面,会有坑
SilentHill
2018-12-18 10:42:40 +08:00
@liuxu 代码问题,time_wait 是由于主动关闭连接方引起的,client 有大量的 time_wait,说明 client 频繁的开关连接,要么使用连接池,要么在同一个连接做尽可能多的事情,避免频繁开关
goofool
2018-12-18 10:43:46 +08:00
改了这些参数问题解决了吗,端口还是会被占用吧。
liuxu
2018-12-18 10:54:30 +08:00
@SilentHill 高负载的时候肯定会有大量 time_wait 吧,特别是做活动某一时间段有高峰流量的时候,新来的 client 远远大于连接池数量的时候
bolide2005
2018-12-18 11:12:30 +08:00
client 主动断开产生 time wait,这是再正常不过的情况,tcp 协议就是这么规定的,楼上一些同学说连接池之类的,还是没有抓住问题的关键,关键在于 3006 是某个应用要监听的端口,但是被 tcp 自动分配的连接给占用了,这种情况,即便使用连接池也无法完全规避,万一(1/(65536-1024))连接池正好占用了 3006 呢?

即便按楼主的方案修改和 time wait 相关的内核参数,也不能完全规避,最多只能把冲突时间降低。我给的建议是修改 /proc/sys/net/ipv4/ip_local_port_range 文件,把 tcp 自动分配的 port range 提高,比如分配范围在 20000~60000,这样一些知名软件预留端口就基本都避开了。
hcymk2
2018-12-18 11:17:35 +08:00
/proc/sys/net/ipv4/ip_local_port_range 这个一般都是很高的吧,除非有人修改过了
Orzpls
2018-12-18 11:19:59 +08:00
@liuxu 提醒各位,不要开这两个参数,开了有反作用,一大堆 RESET,关了就好了,生产环境曾经开过的人留。
xi2008wang
2018-12-18 11:21:00 +08:00
不要随便设置 tcp_tw_reuse,基本没啥用,
还会导致 NAT 环境下用户访问你的服务 时不时丢包导致异常
liuxu
2018-12-18 11:30:40 +08:00
@bolide2005
@hcymk2
@Orzpls

默认最小 32768,楼主 client 能分到 3006,肯定是改过的。

这个很难办,我曾经遇到过这个问题,我司线上服务器默认最小 32768,但也遇到了大量 time_wait 没释放导致无法新开连接的情况,高峰会持续 30-60 分钟,php 日志频繁报“ Cannot assign requested address ”,所以加了那 2 个参数
nekoyaki
2018-12-18 11:32:09 +08:00
楼上有几位提到了 net.ipv4.tcp_timestamps、net.ipv4.tcp_tw_recycle、tcp_tw_reuse,但是这三个参数需要根据实际环境决定是否开启,不能乱开。网上很多二手资料非常误导人。

1、如果开启了 timestamps,但相关机器时间不一致的话,开启 tcp_timestamps 会导致网络连接出现问题,当且仅当你们确定内网涉及到的相关机器都有 ntp 同步时间才能打开。
2、如果关闭 timestamps,recycle 和 reuse 都不生效。网上有的二手垃圾资料教你关闭 timestamps 开启 recycle 和 reuse,没用的。
3、如果确实有 ntp,那么开启 timestamps 和 reuse 就可以了,不要开启 recycle。recycle 是有问题的,新版本内核(4.12)已经废弃了这个参数,reuse 更安全。
fxxkgw
2018-12-18 11:51:20 +08:00
系统内核参数不要乱改,尤其是在 NAT 环境下,网上关于 TIME_WAIT 的资料满天飞,但是绝大多数都是没用的。
1,优化代码,各种 socket 主动关闭
2,最好的办法就是扩容资源。
90928yao
2018-12-18 15:05:16 +08:00
@liuxu 是有啊 但是大量出现这种状态 90%的情况下 是自己代码写得有问题 哈哈,我自己遇到几次了 都是自己代码问题

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/518496

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX