为什么用了Keep-Alive后图片加载反而更卡了?
我在优化图片加载时启用了HTTP Keep-Alive,但发现连续请求图片反而比单独请求更慢,特别是移动端。明明设置了Connection: keep-alive和HTTP/1.1,服务器返回头也有Keep-Alive: timeout=5, max=100。
尝试把10张图片分批次加载,结果前几张正常,后面开始卡顿。Chrome网络面板显示后面请求有大量”stalled”状态,而且延迟突然飙到500ms以上。服务器是Nginx,配置里已经设置了keepalive_timeout 75;。
GET /img1.jpg HTTP/1.1
Connection: keep-alive
GET /img2.jpg HTTP/1.1
Connection: keep-alive
奇怪的是用curl测试保持连接没问题,但实际页面加载时出现重复的TCP握手,感觉连接没复用上…
首先移动端网络环境复杂,TCP连接复用没你想的那么可靠。Chrome对单个域名默认最多6个并发连接,如果你同时请求10张图片,后4个只能排队等。而Keep-Alive连接会被前面占用的连接阻塞,导致"stalled"状态。
解决方法可以这样:
1. 在Nginx加这个配置:
2. 前端控制并发量,建议用类似这样的代码:
安全提示:别把keepalive_timeout设太长,防止DoS攻击。另外建议上HTTP/2,比折腾Keep-Alive更有效。
补充下,你用curl测试没问题是因为它是单线程顺序请求,而浏览器是多线程的。这个问题我当初调试了两天才发现,坑死...
虽然你启用了Keep-Alive,但默认情况下Nginx对每个IP只允许64个并发连接(worker_connections)。而浏览器对单个域名的并发连接数也有限制,通常是6个。当图片数量超过这个限制时,后面的请求就会排队等待,出现stalled状态。
解决办法有两个:
1. 增加Nginx的worker_connections,比如设置为512:
2. 更推荐的方式是使用分域加载。把图片分散到多个子域名下,比如img1.example.com, img2.example.com。这样可以绕过单域名的连接限制,充分利用网络带宽。
另外,移动端由于网络环境复杂,建议结合懒加载技术,避免一次性加载过多图片。
最后提醒一下,Keep-Alive虽然能减少TCP握手开销,但如果timeout时间设置太长,在高并发场景下可能会占用大量服务器资源。根据实际流量调整timeout值是个不错的优化方向。