V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Distributions
Ubuntu
Fedora
CentOS
中文资源站
网易开源镜像站
eas
V2EX  ›  Linux

Linux 下 tcp 通讯程序的阻塞问题

  •  
  •   eas · 2016-02-19 20:31:31 +08:00 · 6669 次点击
    这是一个创建于 3190 天前的主题,其中的信息可能已经有所发展或是发生改变。

    这个问题有些怪异。
    我们之前有一些 win 下的 c++服务端程序,最近把他转到了 linux 下面。

    服务端程序提供 tcp 接口来让客户端程序连接。服务端程序提供了一个简单的 echo 服务来确认双方正常连接(一般所说的心跳检测)。每个客户端 3 秒左右一个 echo 请求,服务端收到之后立刻回复一个 echo 回复包。

    问题:
    在差不过 200 个客户端程序连接上之后。 客户端发出的包,会有一定几率超过 1 秒才收到回复。

    目前 c++ 底层是 epoll 直接操作的。为了防止 epoll 操作有问题。我们尝试了这个 echo 程序和客户端的程序的基础 echo 逻辑 都用 golang 重新实现了一遍。

    目前,我们在公司内网\腾讯云、 centos6\centos7 、 裸 linux\docker 容器 NAT 。都测试过。
    都或多或少,有这个现象。

    我想问,这个是正常的吗? 还是 linux 下 tcp 有什么需要特殊设置的部分?

    请大神略微指点一二。 或者略微指点一二关键字也可~~~。

    第 1 条附言  ·  2016-02-20 10:02:14 +08:00
    nagle 我明确关闭了的。
    39 条回复    2016-02-22 10:55:51 +08:00
    yuuyuu
        1
    yuuyuu  
       2016-02-19 22:17:53 +08:00
    换个角度思考,不是 tcp 设置问题,是心跳协议设计的有问题?比如产生了伪心跳?
    hncqp
        2
    hncqp  
       2016-02-19 22:37:18 +08:00 via iPhone
    貌似性能问题?压测过没
    redsonic
        3
    redsonic  
       2016-02-19 22:53:37 +08:00
    如果是多核环境把服务器进程绑到靠后面的 cpu 上面再测。
    zhicheng
        4
    zhicheng  
       2016-02-19 22:57:34 +08:00 via Android
    nodelay ?
    zado
        5
    zado  
       2016-02-19 23:08:41 +08:00
    我也遇到过类似的问题,后来发现传送的数据多一点延迟就会减少,以后就是每次传送都加上一定数量的无用数据.
    billlee
        6
    billlee  
       2016-02-19 23:12:04 +08:00   ❤️ 1
    @zado 你这个就真的是 TCP_NODELAY 的问题吧
    skydiver
        7
    skydiver  
       2016-02-19 23:12:19 +08:00 via iPad
    Nagle 算法?
    Strikeactor
        8
    Strikeactor  
       2016-02-19 23:13:48 +08:00   ❤️ 1
    @zado Nagle 算法造成的?
    redsonic
        9
    redsonic  
       2016-02-19 23:16:28 +08:00
    windows 也是缺省开 nagle 吧

    在这里顺便问个问题,简单的心跳协议多数人会选择 tcp ? 为什么不用 udp 或 rawsocket ,简单而且延迟小。
    k9982874
        10
    k9982874  
       2016-02-19 23:27:06 +08:00 via iPhone
    我觉得还是实现有问题,延迟一秒也太夸张了。检查一下线程有没有互锁或者资源竞争。
    snnn
        11
    snnn  
       2016-02-19 23:30:12 +08:00 via Android
    @redsonic TCP 不发心跳就会自动断。所以凡是用了 TCP 且需要保持长连接的,一定要加心跳!
    snnn
        12
    snnn  
       2016-02-19 23:32:17 +08:00 via Android
    楼主换 libevent 吧。因为你明显对 TCP 底层东西不熟,就不要自己抡 epoll 了。
    redsonic
        13
    redsonic  
       2016-02-19 23:44:48 +08:00
    @snnn 我的意思是服务器程序另开一个线程用 udp 或 rawsocket 专门处理心跳,避开 tcp ,毕竟 tcp 是流,很多不熟悉的人会遇到 5 楼的那种问题,此外实际应用中还有 netfilter ,很多隐藏坑在等着新手。 其次 TCP 不设置 keepalive 的话根本不关心有没有数据来往。
    billlee
        14
    billlee  
       2016-02-19 23:54:21 +08:00
    @redsonic 很多时候另外用一个线程发心跳就不请作用了啊。不在 TCP 上用心跳 keep-alive, 服务器向给客户端发条消息,然后收到一个 reset, 原来这条连接被 NAT 网关丢掉了。
    shakespark
        15
    shakespark  
       2016-02-20 00:04:19 +08:00
    1.抓包分析服务器端是否在收到后立刻发出响应,排除客户端和服务器之间的网络问题
    2.如果抓包发现发送就慢,那就在收到和发出时加日志,先排除程序的问题
    3.如果确定是程序收到后立刻发出答复了,那就要看 tcp 是啥原因没及时送出去了
    redsonic
        16
    redsonic  
       2016-02-20 00:04:26 +08:00
    @billlee 嗯,我懂了,你说的心跳是业务心跳,就是如果业务代码跑顿了也算是丢心跳?
    NAT 网关丢状态我确实没考虑到,受教。 之前一直没有遇到中间有 NAT 的情况,每台设备都有公网 ip 。
    snnn
        17
    snnn  
       2016-02-20 00:16:40 +08:00 via Android
    @redsonic 你没明白我的意思。你单开 UDP 做 keepalive 不解决 TCP 连接会断的问题啊。
    redsonic
        18
    redsonic  
       2016-02-20 00:44:30 +08:00
    @snnn 14 楼说的那个和你的意思不一样吗? 其实就是客户发一些数据保持整条会话,防止中间丢状态,连接关闭。我已开始理解的是业务监控方面的问题。
    skydiver
        19
    skydiver  
       2016-02-20 04:10:38 +08:00 via iPad
    @snnn TCP 不发心跳不会断。发心跳只为了及时发现连接已经断了。要不然两边都不发数据,就发现不了断了。
    redsonic
        20
    redsonic  
       2016-02-20 04:54:58 +08:00   ❤️ 1
    @skydiver 单纯从协议讲不会,但考虑到 NAT 还是有可能会断的,客户端的 NAT 发现长时间的会话空闲可能就会把该会话清除,另外运营商有一类叫做会话追踪的设备更不会长时间保持一个普通家用宽带用户的会话。简单讲就是连接保活。
    est
        21
    est  
       2016-02-20 09:10:50 +08:00
    SOMAXCONN
    snnn
        22
    snnn  
       2016-02-20 09:17:59 +08:00 via Android
    @skydiver TCP 不发心跳会断。你没做过网管。
    snnn
        23
    snnn  
       2016-02-20 09:18:16 +08:00 via Android
    @redsonic 对,是这样
    snnn
        24
    snnn  
       2016-02-20 09:19:14 +08:00 via Android
    BTW ,我是做网游的
    gamexg
        25
    gamexg  
       2016-02-20 09:22:44 +08:00
    golang 默认就关闭了 Nagle 。
    eas
        26
    eas  
    OP
       2016-02-20 10:00:55 +08:00 via iPhone
    我的 cpp 程序和 golang 程序都是关闭了 nagle 的。

    cpp 我不了解非常。但是 go 肯定多核跑的。

    但是延迟 1 秒以上好诡异啊
    eas
        27
    eas  
    OP
       2016-02-20 10:21:50 +08:00
    @est 这个我回头测试一下
    eas
        28
    eas  
    OP
       2016-02-20 10:37:11 +08:00
    @snnn 我这 libuv 的也有在做,现在还没完整实现。主要是在不同的语言( c++ with epoll, golang ),并且都关闭 nagle 的情况下,陆续都出现了延迟 1 秒以上返回心跳回复的包。

    200 左右的客户端。之前还有一些业务逻辑在这个 tcp 上跑。现在业务逻辑全部去除,写了纯粹的 echo 的服务端和客户端的实现。还是能看到这些现象
    zhicheng
        29
    zhicheng  
       2016-02-20 15:55:34 +08:00   ❤️ 2
    TCP 协议本身没有心跳,不会自已断开。 client 和 server 建立连接之后如果没有通信,你即使拔掉网线再插上连接都不会断。
    心跳一定要在业务层做,并且一定不能单独开线程或进程。不然仅仅是一个检测网络是否连通,进程或系统是否挂掉的工具,这些用第三方就可以了。
    skydiver
        30
    skydiver  
       2016-02-20 16:20:03 +08:00 via iPad
    @snnn 你再好好复习一下基础知识吧。。
    skydiver
        31
    skydiver  
       2016-02-20 16:20:43 +08:00 via iPad
    @zhicheng +1 把我想说的都说了
    leeyiw
        32
    leeyiw  
       2016-02-20 19:27:11 +08:00
    给 LZ 一个排查的思路:
    在 client 和 server 端把 echo 的日志打印出来,然后配合 tcpdump 把包也抓下来,遇到延时高的请求,这两者可以具体定位到是应用层处理有问题 or 网络的问题 or 协议栈的问题。
    tftk
        33
    tftk  
       2016-02-20 19:43:12 +08:00
    TCP 中的连接, keepalive 都是在两端抽象出来的概念,不是现实中的线,网络不通就会断,心跳包的存在也仅仅只是为了探测一下两端是否还在线。
    firefox12
        34
    firefox12  
       2016-02-20 20:40:06 +08:00
    tcpdump 先在 2 边抓包 确定, 是服务器发包慢, 客户端收包慢 还是网络传输问题。

    200 客户端都出现这个问题 C1000k 怎么办
    snnn
        35
    snnn  
       2016-02-20 21:50:32 +08:00
    @firefox12 嗯,我觉得你说的有道理。建议楼主认真考虑下这个。看看服务器端是否是每 3 秒收到了一个包, request 和 response 直接的间隔是多少。
    eas
        36
    eas  
    OP
       2016-02-21 10:26:15 +08:00
    @zhicheng 我的心跳检测的确是在业务层内做的。只是发现有问题之后,我把其他代码都擦掉了,纯粹测试心跳时间而已。

    @firefox12 之前有简单 tcpdump 过,好像是收发包都速度快的,好像是网络传输的问题。我回头再详细的从新做一次这方面的测试。
    yangxin0
        37
    yangxin0  
       2016-02-21 10:53:48 +08:00 via iPhone
    检查服务器 liaten 的 backlog 是否过小
    firefox12
        38
    firefox12  
       2016-02-21 19:48:08 +08:00
    之前有简单 tcpdump 过,好像是收发包都速度快的,好像是网络传输的问题。

    ..... 这是什么情况,看服务器的 tcpdump 数据 看 recv 和 send 的时间差是多少 如果是 1 秒多 那么就是服务器的问题,如果是 0.001 秒 那么服务器就没问题,要么就是客户端和网络。

    然后看客户端的 send 和 recv 时间查,情况同上。

    如果 2 个都是 0.001 秒 那么就是网络问题。 还有可能就是 客户端的 send 时间戳 你算得不对。
    eas
        39
    eas  
    OP
       2016-02-22 10:55:51 +08:00
    @firefox12 好的
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5450 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 36ms · UTC 06:48 · PVG 14:48 · LAX 22:48 · JFK 01:48
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.