V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
a663
V2EX  ›  程序员

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

  •  
  •   a663 · 2018-12-18 09:51:20 +08:00 · 4348 次点击
    这是一个创建于 2166 天前的主题,其中的信息可能已经有所发展或是发生改变。

    当时忙是旁边小哥遇到处理的,但是最后问题原理 他也没说不明白 问题情形: 一个应用要使用 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 )会有什么坑留下?

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

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

    网络环境越好出现概率越低,要同时满足:主动关闭一端已经结束、有包被阻塞在途中且最后成功被送达、正好有同样端口的新连接这几个条件,才会出现混乱。
    a663
        8
    a663  
    OP
       2018-12-18 10:28:37 +08:00 via Android
    @liuxu 关闭本机的 timestamps 是为了避免 recycle NAT 后的坑吧?但是这样子不会对本机带来什么坑么?
    a663
        9
    a663  
    OP
       2018-12-18 10:31:16 +08:00 via Android
    @liuxu 记错了 这样子操作,主机 NAT 在后面,会有坑
    SilentHill
        10
    SilentHill  
       2018-12-18 10:42:40 +08:00
    @liuxu 代码问题,time_wait 是由于主动关闭连接方引起的,client 有大量的 time_wait,说明 client 频繁的开关连接,要么使用连接池,要么在同一个连接做尽可能多的事情,避免频繁开关
    goofool
        11
    goofool  
       2018-12-18 10:43:46 +08:00
    改了这些参数问题解决了吗,端口还是会被占用吧。
    liuxu
        12
    liuxu  
       2018-12-18 10:54:30 +08:00
    @SilentHill 高负载的时候肯定会有大量 time_wait 吧,特别是做活动某一时间段有高峰流量的时候,新来的 client 远远大于连接池数量的时候
    bolide2005
        13
    bolide2005  
       2018-12-18 11:12:30 +08:00   ❤️ 2
    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
        14
    hcymk2  
       2018-12-18 11:17:35 +08:00
    /proc/sys/net/ipv4/ip_local_port_range 这个一般都是很高的吧,除非有人修改过了
    Orzpls
        15
    Orzpls  
       2018-12-18 11:19:59 +08:00 via Android
    @liuxu 提醒各位,不要开这两个参数,开了有反作用,一大堆 RESET,关了就好了,生产环境曾经开过的人留。
    xi2008wang
        16
    xi2008wang  
       2018-12-18 11:21:00 +08:00
    不要随便设置 tcp_tw_reuse,基本没啥用,
    还会导致 NAT 环境下用户访问你的服务 时不时丢包导致异常
    liuxu
        17
    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
        18
    nekoyaki  
       2018-12-18 11:32:09 +08:00   ❤️ 3
    楼上有几位提到了 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
        19
    fxxkgw  
       2018-12-18 11:51:20 +08:00   ❤️ 1
    系统内核参数不要乱改,尤其是在 NAT 环境下,网上关于 TIME_WAIT 的资料满天飞,但是绝大多数都是没用的。
    1,优化代码,各种 socket 主动关闭
    2,最好的办法就是扩容资源。
    90928yao
        20
    90928yao  
       2018-12-18 15:05:16 +08:00
    @liuxu 是有啊 但是大量出现这种状态 90%的情况下 是自己代码写得有问题 哈哈,我自己遇到几次了 都是自己代码问题
    liuxu
        21
    liuxu  
       2018-12-18 15:43:37 +08:00
    @90928yao 嗯,是有办法减少资源占用,我遇到的是 php 到 mysql 链接太多导致的
    petelin
        22
    petelin  
       2018-12-18 16:32:00 +08:00
    基本上服务端总是主动断掉链接, 都是代码没写好 /库有问题, 链接服务, 都是 http 长链接之类的吧, 那会创建一个请求一下,然后关掉(我能想到的只有及特殊的爬虫会这样).
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3632 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 35ms · UTC 10:19 · PVG 18:19 · LAX 02:19 · JFK 05:19
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.