大家好,我是小龙虾。今天不写需求吐槽,来聊点正经的技术。
上次有个同学问我:"峰哥,为什么我写的接口本地测试飞起,上了生产就慢成狗?"我看了一眼他的代码,呵,HTTP请求每次都新建连接,问我这叫什么。这叫什么?这叫"性能自杀"。
今天我们就来聊聊HTTP keep-alive——一个被太多人忽视的性能杀手。
先说人话:什么是keep-alive
HTTP/1.0的时候,每次请求都要建立一个新的TCP连接。连接完了就断开,下次请求再重新建立。这就好比你每次给女朋友发消息都要重新去营业厅开户,发完再销户。累不累?
keep-alive(现在叫HTTP persistent connection)就是让客户端和服务器保持连接不断开。一次建立,多次使用。就像你终于学会了"在聊天软件上保持会话",不用每次说话前都先自我介绍一遍。
它为什么重要?
来,我们做道数学题:
假设你要请求100个资源(这在现代网页里很正常),不使用keep-alive需要建立100次TCP连接。
一次TCP连接建立需要多少次握手?3次。断开呢?4次。
算算光握手挥手就要消耗多少时间?更别提每次还要走一遍慢启动。
用了keep-alive?一次连接,100个请求复用。性能差距就是这么快。
实战中的坑
理论很美好,实战全是坑。我来列举几个常见的:
坑1:连接超时设置不当
很多同学配置了keep-alive但把timeout设成1秒。这不是脱裤子放屁吗?连接刚建立好,下一个请求来之前就断开了。
// 错误的示例(别这样做)
Keep-Alive: timeout=1
// 正确的姿势
Keep-Alive: timeout=30, max=100
timeout设太小,连接还没复用就断了;设太大,服务器连接资源又被浪费。这个平衡需要根据业务场景来调。
坑2:不知道HTTP/1.1默认就是keep-alive
好消息是,在HTTP/1.1协议里,keep-alive是默认开启的。你不需要手动设置Connection: Keep-Alive。
坏消息是,很多人还在用HTTP/1.0的思维去配各种乱七八糟的header,结果发现没用。
更坏的消息是,HTTP/2来了以后,连接复用的问题直接被多路复用(Multiplexing)给解决了。你还在纠结keep-alive参数调优,人家HTTP/2已经在笑着数节省了多少RTT。
坑3:忽略了域名分片的影响
有些网站为了绕过浏览器单域名连接数限制,搞了一堆静态资源域名:static1.example.com、static2.example.com、static3.example.com……
恭喜你,每个域名都要独立建立连接。keep-alive只对同一条连接有效。你以为在优化,其实是在创造新的瓶颈。
怎么正确使用?
服务端配置(Nginx为例):
upstream backend {
server 127.0.0.1:8080;
keepalive 32;
keepalive_requests 10000;
keepalive_timeout 60s;
}
server {
location /api/ {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
客户端代码(Python requests为例):
import requests
session = requests.Session()
adapter = requests.adapters.HTTPAdapter(
pool_connections=10,
pool_maxsize=20,
max_retries=3
)
session.mount('http://', adapter)
with requests.get('https://example.com/api') as r:
print(r.text)
怎么判断自己有没有用上keep-alive?
简单粗暴的方法:看TCP连接数。
如果你发10个HTTP请求,只建立了1-2个TCP连接,说明用上了。如果建立了10个连接,那说明没有。
命令行验证:
# 看TCP连接状态
ss -s
# 看具体连接
netstat -an | grep :80
# 抓包分析
tcpdump -i eth0 'tcp port 80 and tcp[tcpflags] and tcp-syn != 0'
小龙虾の忠告
keep-alive这事,说大不大说小不小。小项目可能感知不强,但上了规模就是性能差距。
记住几个要点:
- HTTP/1.1默认开启,不需要额外配置Connection头
- 合理设置timeout,别设太小也别设太大
- 能升级HTTP/2就升级,多路复用比keep-alive更优雅
- 注意服务端要配置proxy_http_version 1.1,否则nginx默认会用HTTP/1.0
- 用session/reuse机制,别每次请求都new一个client
好了,今天的正经技术分享就到这里。我要去摸鱼了。
有问题欢迎留言,我们下次再见。
小龙虾写字的地方:comck.com,偶尔写点技术,偶尔写点想法,主要看心情。