优化 Nginx 减少 TCP 握手延迟的核心是启用长连接(Keepalive)并开启内核级文件传输(sendfile)。适用场景为高并发静态资源服务,风险边界在于过长的 keepalive_timeout 可能占用过多 worker 连接数。
先说结论:通过复用 TCP 连接和减少内核态拷贝可降低延迟,但需根据并发量调整连接保持时间。
- 先定位:确认当前连接是否频繁新建,检查 access 日志中的连接状态。
- 先做:开启 keepalive_timeout、sendfile 和 tcp_nopush 参数。
- 再验证:使用 curl 多次请求观察 Connection 头部是否保持 alive。
命令速用版
以下配置片段可直接放入 nginx.conf 的 http 块中,用于启用基础优化:
http { keepalive_timeout 65; keepalive_requests 100; sendfile on; tcp_nopush on; tcp_nodelay on; open_file_cache max=1000 inactive=20s;}
为什么会这样
TCP 握手需要三次往返通信,频繁握手会显著增加首包延迟。
启用 keepalive 后,客户端与服务器之间的 TCP 连接在请求结束后不会立即关闭,后续请求可复用该连接,避免重复握手。sendfile 指令允许 Nginx 直接在内核空间传输文件数据,避免数据在用户态和内核态之间拷贝,减少 CPU 占用并提升大文件传输效率。tcp_nopush 配合 sendfile 使用,确保数据包填满后再发送,减少网络碎片。
分步处理
第一步:调整连接保持参数
在 http 块中设置 keepalive_timeout,默认值通常较短,建议设置为 60 秒至 75 秒之间。设置 keepalive_requests 限制单个连接上的最大请求数,防止单个连接长期占用。
配置示例:
keepalive_timeout 65;keepalive_requests 100;
第二步:开启内核传输优化
确认操作系统支持 sendfile 系统调用(Linux 通常默认支持)。在配置中开启 sendfile 及相关 TCP 参数。
配置示例:
sendfile on;tcp_nopush on;tcp_nodelay on;
第三步:配置文件缓存
使用 open_file_cache 缓存文件描述符和元数据,减少磁盘 I/O 查找开销。适用于静态文件数量较多且频繁访问的场景。
配置示例:
open_file_cache max=1000 inactive=20s;open_file_cache_valid 30s;open_file_cache_min_uses 2;
回滚提醒:修改配置前务必备份 nginx.conf,每次修改后执行 nginx -t 测试配置合法性,再执行 nginx -s reload 重载。
怎么验证是否生效
检查配置是否加载:
执行命令 nginx -T,查看输出中是否包含上述配置指令。
验证连接复用:
使用 curl 命令发起两次请求,观察响应头中的 Connection 字段。
命令示例:
curl -I http://your_domain/static/file.jscurl -I http://your_domain/static/file.css
若响应头显示 Connection: keep-alive,且两次请求之间 TCP 连接未断开(可通过 tcpdump 或 ss 命令观察状态),说明 keepalive 生效。
验证 sendfile 状态:
查看 Nginx 错误日志,若 sendfile 不支持通常会报错。在大文件下载时观察服务器 CPU 占用率,开启 sendfile 后 CPU 占用应明显低于未开启状态。
常见坑
1. NFS 磁盘不支持 sendfile
如果静态文件存储在 NFS 网络文件系统上,sendfile 可能无法正常工作或导致文件损坏。此时需在 location 块中关闭 sendfile:sendfile off;。
2. keepalive_timeout 设置过长
过长的保持时间会导致 worker 进程持有的连接数过多,在高并发下可能耗尽 worker_connections 配额,导致新连接被拒绝。需根据服务器内存和并发量权衡。
3. 动态内容误用 sendfile
sendfile 仅对静态文件有效,对 FastCGI 或 proxy_pass 生成的动态内容无效。无需在全局强制关闭,Nginx 会自动处理,但需确保静态文件 location 正确匹配。
常见问题
keepalive_timeout 设置多少合适?
建议设置在 60 秒至 75 秒之间,既能覆盖浏览器默认保持时间,又不会过度占用服务器连接资源。
开启 sendfile 会影响动态内容吗?
不会,sendfile 仅作用于静态文件读取,动态内容通过 FastCGI 或代理生成,不受该参数影响。
worker_connections 设多少比较好?
取决于服务器内存和预期并发,公式通常为 最大并发数 / worker 进程数,需确保系统文件描述符限制(ulimit -n)足够大。
参考来源
- Nginx official documentation, Module ngx_http_core_module, http://nginx.org/en/docs/http/ngx_http_core_module.html
- Nginx official documentation, Module ngx_http_static_module, http://nginx.org/en/docs/http/ngx_http_static_module.html