前阵子接手一个老项目的性能复查,压测一上来,接口的p99延迟直接从30ms飙到1.2s,错误率也跟着往上窜。带过团队的朋友都懂这种抓狂感:代码 review 了好几轮,业务逻辑看不出毛病,数据库连接池、缓存都查过,最后只剩下网络IO这条链路没彻底扒干净。网络IO性能优化这件事,从TCP到HTTP,每一层都有能压的空间,但也埋着不少坑。这篇我把当时做全链路优化的思路、参数、实测数据和踩坑记录整理出来,给正在排查慢接口、高并发连接问题的后端开发或运维一个可以照着重试的参考。文章不绕弯子,直接按优化顺序讲,适合有一定网络基础、想系统化排查问题的人。
1. 优化前的现状与问题拆解
1.1 先看清楚瓶颈在哪一层
很多项目一提到网络慢,第一反应是加带宽或者换服务器,其实大部分问题不在物理带宽,而在连接管理和协议开销。网络IO性能优化,本质上是在四个维度里找最短的那个板:连接建立效率、数据传输路径、协议封装开销、系统资源上限。
我习惯用一个比较形象的类比:TCP相当于Road,HTTP相当于路上的车。如果路不宽,车一多路口就堵;如果路很宽,但每辆车到收费口都要重新走一遍证件查验流程,那平均速度照样起不来。连接建立就是那个“证件查验”,HTTP请求体就是“货物”,TCP内核栈就是“路政管理”。优化时不能只盯着单点,要把整条链路拆成一段一段看。
当时观察到的现象是:压力测试一上并发,TIME_WAIT状态的连接数量迅速飙到几万,然后新连接开始报错,接口响应也跟着劣化。这个信号基本可以判断,问题主要出在TCP连接管理和HTTP连接复用上,和代码逻辑关系不大。所以第一步不是填业务代码的坑,而是把连接的全生命周期捋一遍。
1.2 TCP三次握手与四次挥手:被忽略的固定成本
TCP连接不是免费的。一次完整的连接建立,需要三次握手:客户端发SYN,服务端回SYN+ACK,客户端再回ACK。在没有额外延迟的情况下,这至少消耗1.5个RTT(Round-Trip Time,往返时间)。如果客户端和服务器之间的RTT是40ms,那么新建一个连接光是握手就花掉60ms,还没开始传输数据。
这里说的RTT还不包括TLS层。如果服务开了HTTPS,一次TLS握手通常会额外消耗1到2个RTT,有些复杂的证书链或者DH协商会更久。也就是说,一个全新的HTTPS连接在真正发HTTP请求之前,可能已经消费了3到4个RTT。想想看,如果客户端采用串行请求,每次请求都重新建连,100个请求光建连就是上百毫秒到几百毫秒的时间,压测数据自然难看。
断开连接也有成本。四次挥手过程中,主动关闭方会进入TIME_WAIT状态,需要等待2个MSL(最大报文段生存时间),Linux上默认大约60秒。短连接多的时候,系统里会堆积大量TIME_WAIT socket,占用本地端口和连接表资源。这也是压测中非常典型的“连接数高、性能差”的根源。
1.3 HTTP协议形态直接决定了连接怎么用
再看HTTP这一层。HTTP/1.0默认是短连接,每个请求都单独走一次TCP建连和断开,基本等于把三次握手的开销重复N遍。HTTP/1.1支持了Keep-Alive,默认开启长连接,这是一次重要的性能解放,但很快暴露出另一个问题:队头阻塞。
HTTP/1.1在同一个连接上发送请求时,必须等上一个响应完全返回才能继续发下一个,浏览器通常会对同一域名开6个左右的连接来缓解,但背后的代码如果没走连接池,或者框架配置不对,依然可能一次性创建大量短连接去请求,反而拖垮系统。用Go、Java、Python做HTTP客户端时,如果不显式设置连接复用,默认行为在不同版本下还不一样,特别容易踩坑。
所以TCP和HTTP是强耦合的:TCP层决定连接能不能高效复用,HTTP层决定业务上要怎么利用这批连接。两层一起看,才能把耗时真正降下来。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 从TCP到HTTP:关键参数的优化思路
2.1 TCP层能动的内核参数与落点
TCP层优化主要落在系统内核参数和应用程序socket选项上。下面是当时测试环境里调整过的一组参数,具备普遍性,但每台机器和业务场景不同,请先理解再抄。
bash复制# /etc/sysctl.conf 追加后执行 sysctl -p
net.core.somaxconn = 1024
net.ipv4.tcp_max_syn_backlog = 4096
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_tw_reuse = 1
net.i
