HTTP/2协议在Nginx中的实现包含一组与推送(Push)相关的指令,其中推送日记(Push Diary)是控制服务端重复推送行为的核心机制。不少人在配置HTTP/2时只关注多路复用带来的并发提升,却忽略了推送日记的维护成本。当日记条目不断累积而没有及时清理时,连接内存会被无谓占用,极端情况下甚至影响并发连接数。这篇文章就来聊聊推送日记的清理间隔相关配置,以及围绕HTTP/2推送的完整调优思路。

什么是推送日记,为什么需要清理
HTTP/2的Server Push允许服务端在客户端还没有发出请求的情况下,主动把页面依赖的CSS、JS等资源推送过去,省去一次往返。听起来很美好,但如果客户端缓存里已经有了这些资源,推送反而变成带宽浪费。推送日记就是服务端为每个连接维护的一张记录表,记下已经推送过哪些URL,下次准备推送时先查表,命中就跳过。
这张表本身是存在内存里的,每一条记录都包含URL的哈希摘要。Nginx通过http2_push_diary_size指令控制日记容量,默认值是256条。容量越大,去重效果越好,但单个连接占用的内存也越多。日记的淘汰与整理是按周期执行的,当条目达到上限或者超过设定的检查周期时,Nginx会对日记做一次整理,移除过期和重复的条目,这就是所谓的清理动作。
需要注意的是,清理并不是一个独立暴露给用户的定时器指令,它和连接的生命周期绑定在一起。理解这一点的意义在于:与其纠结清理间隔本身,不如从日记容量、推送范围、连接复用时长三个维度一起调整,才能达到理想效果。
相关配置指令详解与示例
先看一组完整的HTTP/2推送配置。Nginx中真正直接暴露的指令是http2_push、http2_push_preload和http2_push_diary_size,清理行为由Nginx内部结合容量上限自动触发:
server {
listen 443 ssl http2;
server_name www.ipipp.com;
# 日记容量,控制每个连接最多记录多少条推送历史
http2_push_diary_size 512;
# 显式推送指定资源
location /index.html {
http2_push /static/style.css;
http2_push /static/app.js;
}
# 通过Link头配合preload自动推送
location /static/ {
http2_push_preload on;
add_header Link "</static/font.woff2>; as=font; rel=preload";
}
}
上面配置中,http2_push_diary_size设为512,意味着单连接的日记表最多保留512条记录。当达到上限时,Nginx会触发内部整理逻辑,旧的条目会被新条目覆盖。如果你想降低内存占用,可以把值调小到64或128;反之,如果站点静态资源非常多且用户会话较长,适当调大能减少重复推送的概率。
推送真的值得开吗:现状与替代方案
这里必须提一个重要的行业事实:Chrome和Firefox已经相继在浏览器端禁用了对HTTP/2 Push的支持,原因是推送命中率长期偏低,收益无法覆盖复杂度。取而代之的是103 Early Hints状态码,它让浏览器在服务器还没生成完整响应时就开始预取关键资源。
如果你的用户主要使用现代浏览器,开启Server Push的实际收益微乎其微,反而要为每个连接维护推送日记。这种情况下更务实的做法是关闭推送,专注于HTTP/2多路复用、头部压缩本身的收益,再配合CDN、资源预加载提示(rel=preload)等手段优化首屏。
对于仍在使用支持推送的老旧客户端的内网环境或特定App的WebView场景,推送仍有价值。此时的调优建议是:只推送首屏必需的关键CSS,控制在3到5个资源以内;日记容量保持默认或略高;同时在access日志中记录推送行为,观察命中率,如果低于七成就应该收缩推送范围。
排查与验证推送效果的实用方法
配置完成后如何验证?最直接的方式是用curl的HTTP/2支持查看推送流。执行类似curl -kv --http2 https://www.ipipp.com/index.html的命令,在输出中能看到PUSH_PROMISE帧的踪迹。浏览器开发者工具的Network面板中,被推送的资源也会带有特殊标记。
# 查看Nginx编译时是否包含http_v2_module nginx -V 2>&1 | grep -o http_v2_module # 用curl验证推送,观察PUSH_PROMISE相关输出 curl -kv --http2 https://www.ipipp.com/index.html # 在日志中记录推送情况,便于统计命中率 # log_format中可加入 $http2 变量判断协议版本 log_format push '$remote_addr [$time_local] http2=$http2 "$request"';
除了验证,监控也要跟上。可以通过nginx -T确认配置已生效,结合状态模块观察连接内存水位。如果发现worker进程内存在推送开启后明显上涨,优先怀疑日记容量设置过大或者推送资源清单过长,逐步收缩后再观察。总之,推送日记的清理与容量管理是一个整体,理解了它和连接生命周期的关系,配置起来就不会盲目照抄网上的参数了。