Nginx的日志系统提供了大量内建变量,其中$connection_requests是一个容易被忽视但非常实用的变量。它表示当前连接上已经处理的请求总数,换句话说,一条TCP连接从建立到关闭期间,通过它发送过多少个HTTP请求,这个数字就是$connection_requests的值。在开启keepalive的情况下,这个变量可以直接用来衡量连接复用程度,是分析长连接效率的重要依据。

$connection_requests的工作原理
要理解这个变量,首先要从HTTP keepalive机制说起。在没有长连接的时代,客户端每发起一个请求都要经历TCP三次握手、发送请求、接收响应、四次挥手这整个过程,一个连接只承载一个请求。而在HTTP/1.1默认开启keepalive之后,一条TCP连接可以被多个请求复用,第一个请求完成后连接并不关闭,后续请求继续在这条连接上传输。
Nginx内部为每个连接维护一个计数器,该连接每完整处理一个请求,计数器就加一。$connection_requests读取的正是这个计数器的值。注意它统计的是请求数,而不是字节数或报文数,即使一个请求分多个TCP段到达,也只算一个请求。当连接因为超时或达到keepalive_requests上限而关闭后,这个计数器随之销毁,下次新连接会重新从1开始计数。
可以通过一个简单实验验证:使用curl的同一个连接连续请求两次同一地址,观察日志中$connection_requests的值。
curl -v http://127.0.0.1/test http://127.0.0.1/test 2>&1 | grep -i 're-using' # 日志中第二条记录的connection_requests值为2
在日志中配置并使用该变量
要使用这个变量,最常见的方式是把它加入log_format。默认的combined格式并不包含它,需要自定义格式。下面是一个完整的配置示例:
http {
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"conn_id=$connection conn_reqs=$connection_requests" '
'req_time=$request_time';
access_log /var/log/nginx/access.log main;
keepalive_timeout 65;
keepalive_requests 1000;
}配置中的$connection是连接的序号,它与$connection_requests搭配使用效果最好。通过这两个字段可以在日志中还原每条连接的生命周期:同一个conn_id的多条日志,conn_reqs值递增,最后一条就是这条连接总共处理的请求数。
分析日志时有一个小技巧。用awk按conn_id分组取最大值,就能得到每条连接的请求总数分布:
awk '{match($0, /conn_id=([0-9]+)/, a); match($0, /conn_reqs=([0-9]+)/, b);
if (b[1]+0 > max[a[1]]) max[a[1]] = b[1]+0}
END {for (i in max) print max[i]}' /var/log/nginx/access.log | sort -n | uniq -c如果大部分连接的最大请求数都是1,说明长连接几乎没有被复用,可能是客户端不支持或者keepalive_timeout设置过短;如果请求数普遍接近keepalive_requests的值,说明复用非常充分,甚至可以考虑调大上限以减少连接建立开销。
与keepalive相关指令的配合调优
keepalive_requests指令限制了单条连接最多能处理的请求数,达到上限后Nginx会主动关闭连接,客户端需要重新建连。默认值在不同版本中有所不同,新版本默认为1000。这个上限和$connection_requests是直接挂钩的:日志中该变量的值永远不会超过keepalive_requests设定的数字。
keepalive_timeout则决定了连接空闲多久后被关闭。如果它设置得太短,比如只有几秒,客户端还没来得及发送下一个请求连接就被关了,$connection_requests自然就一直是1。反过来,如果设置得很长而客户端请求稀疏,会占用大量空闲连接,在并发高的场景下可能耗尽连接资源。一般建议根据业务请求间隔设置,常见的值在30到75秒之间。
还有一个容易混淆的点:$connection_requests统计的是Nginx视角的请求,经过代理或负载均衡时,如果前置设备每请求都新建到后端的连接,后端日志里这个变量的值会普遍偏小。因此在排查长连接问题时,要在链路上的每一层分别观察,判断复用在哪一环断了。比如LVS或某些配置不当的四层转发会把每个请求转发到不同后端连接,这时即使客户端支持keepalive,后端看到的请求数依然分散。
实际排查案例
p一个典型场景是接口响应耗时突然上升。有运维人员通过日志发现,同一conn_id的请求间隔远小于keepalive_timeout,但每次$connection_requests都为1,进一步抓包确认是客户端SDK每次请求都显式带上了Connection: close头,导致连接无法复用,大量时间消耗在握手与挥手。修正客户端配置后,连接复用率显著提升,平均延迟下降。另一个场景是反向代理场景下调优upstream的keepalive。upstream块中的keepalive指令控制Nginx到后端的长连接数,配合proxy_http_version 1.1和proxy_set_header Connection ""使用。通过在后端服务的访问日志里观察$connection_requests,可以直接验证upstream长连接是否生效:生效后该值会明显大于1,否则基本为1。
upstream backend {
server 192.168.0.1:8080;
keepalive 64;
}
server {
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}总的来说,$connection_requests是一个观察连接行为的窗口,单独看意义有限,但与$connection、$request_time、keepalive配置结合分析,就能快速定位连接复用问题、评估长连接调优效果。养成在自定义日志格式中保留这个变量的习惯,排查问题时会省去不少抓包的麻烦。
Nginx$connection_requests连接请求数修改时间:2026-09-07 09:48:36