deferred 参数启用内核TCP_DEFER_ACCEPT机制,使Nginx仅在客户端发送首数据包后才accept连接,减少空连接资源消耗;需配合listen地址使用,支持IPv6和reuseport,不支持UNIX socket。

Nginx 的 deferred 参数本质是启用内核级的 TCP 延迟 accept 机制(Linux 下对应 TCP_DEFER_ACCEPT),它让 worker 进程不参与空连接的建立过程,只在客户端真正发送 HTTP 请求数据后才介入处理。这能减少无效连接占用资源、降低 epoll 等系统调用频率,对高并发短连接场景有明显吞吐提升。
deferred 的作用原理
- 普通模式下:三次握手一完成,内核就把连接放入全连接队列,Nginx 立即调用
accept()获取 socket,并分配 worker 处理(哪怕客户端还没发任何数据)。 - 启用
deferred后:三次握手完成后,连接仍留在内核队列中;只有当客户端紧接着发送了第一个数据包(如GET / HTTP/1.1),内核才把该连接交付给 Nginx,触发accept()和 worker 调度。 - 效果:避免大量“建连即断”或“建连后长时间空闲”的连接消耗 worker 连接数、内存和事件循环开销。
如何正确配置 deferred
deferred 是 listen 指令的可选参数,只能加在 server 块中,且需配合具体监听地址使用:
server {
listen 80 deferred;
listen 443 ssl deferred;
listen 127.0.0.1:8000 deferred;
# 注意:不能单独写 listen deferred; —— 必须带地址或端口
}- ✅ 支持组合:可与其他参数共存,例如
listen 80 default_server backlog=4096 rcvbuf=64k sndbuf=64k deferred; - ✅ IPv6 兼容:
listen [::]:80 deferred;有效 - ❌ 不支持 UNIX socket 监听(仅适用于 TCP)
- ❌ FreeBSD 上需搭配
accept_filter=dataready,Linux 下直接生效
配合优化的建议项
单纯加 deferred 有收益,但效果更佳时建议同步调整:
-
增大
backlog:防止因延迟 accept 导致全连接队列溢出丢包listen 80 backlog=8192 deferred;
-
启用
reuseport(Linux 3.9+):让每个 worker 拥有独立监听 socket,进一步分摊连接建立压力listen 80 reuseport deferred;
-
确认内核参数合理:检查
net.core.somaxconn是否 ≥backlog设置值(默认常为 128,生产环境建议设为 65535)sysctl net.core.somaxconn
实际影响与注意事项
- 对长连接(keepalive)无负面影响,因为首次请求已触发 accept,后续请求复用已有连接。
- 若客户端建连后长期不发数据(如恶意慢速攻击),连接会在内核层面超时释放(由
tcp_fin_timeout和tcp_keepalive_*控制),不占用 Nginx worker。 - 日志中
$connection或$request_time不会因此失真,Nginx 记录的时间点仍是实际收到请求数据的时刻。 - 不推荐在调试阶段开启:
curl -v http://localhost可能因未发完整请求而卡住或报错,排查问题时建议临时关闭。
不复杂但容易忽略。


















