epoll_wait存在40ms延迟导致低吞吐量问题求助
TCP本地连接下epoll_wait 40ms延迟问题排查与解决
场景与异常表现
- 客户端与服务端部署在同一机器,通过
127.0.0.1建立TCP连接 - 客户端分两次调用
send():先发送56字节消息头部,再发送512字节消息主体 - 服务端基于
epoll_wait()监听连接事件,调用recv()接收数据 - 异常:第二次
epoll_wait()出现40ms延迟,导致吞吐量仅约11kB/s
客户端时间戳日志
[ 1585038.0005] start send 56 [ 1585038.0006] end send 56 [ 1585038.0006] start send 512 [ 1585038.0006] end send 512
服务端时间戳日志
[ 1585038.0002] epoll_wait [ 1585038.0006] start recv 56 [ 1585038.0006] recv return 56 [ 1585038.0006] start recv 512 [ 1585038.0006] recv return -1 [ 1585038.0006] epoll_wait [ 1585038.0442] epoll_wait return 1 [ 1585038.0443] start recv 512 [ 1585038.0443] recv return 512
原因分析
延迟是Nagle算法与**TCP延迟确认(Delayed ACK)**共同作用的结果:
- 客户端发送56字节后,服务端成功接收,但TCP延迟确认机制默认会延迟40ms再发送ACK(Linux系统默认配置)
- 客户端发送512字节时,Nagle算法(默认开启)会等待前一包的ACK返回后再发送当前包,导致512字节被暂存
- 40ms后服务端发送延迟ACK,客户端才将512字节发出,服务端的
epoll_wait()此时才被唤醒,出现明显延迟
解决方法
- 关闭Nagle算法:在客户端设置
socket的TCP_NODELAY选项,让小数据包立即发送,无需等待ACK:int flag = 1; setsockopt(client_fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)); - 合并发送数据:将56字节头部与512字节主体合并为一个缓冲区,一次性调用
send()发送,避免触发Nagle算法的等待逻辑 - 调整ACK时机:服务端在接收头部后,立即通过应用层响应或空包触发ACK发送,避免延迟确认(不推荐修改系统全局TCP参数)
内容的提问来源于stack exchange,提问作者yuanjianpeng
相关产品推荐
相关产品推荐

