上一篇 下一篇 分享链接 返回 返回顶部

日本服务器部署网站缓存时,页面缓存与失效规则如何设置

发布人:Minchunlin 发布时间:2 天前 阅读量:13
日本服务器部署网站缓存时,页面缓存与失效规则如何设置

页面更新了,访问者却还看到旧内容

常见的运维现场是这样的:网站部署在日本服务器上,编辑已经发布新文章,站长在后台也能看到新版本,但未登录的访问者仍看到旧页面;清理浏览器后有所变化,部分访问者却依旧看不到更新。这时不能直接认定“服务器缓存没清干净”。旧内容可能留在浏览器、边缘节点、页面代理,或者应用内部的对象与查询缓存中。

页面缓存的设置原则是:只让明确可公开、对不同访问者内容相同的页面进入缓存;把登录态、预览、购物流程及未核实用途的查询参数排除;先用较短有效期运行,再根据发布要求决定是否需要主动失效。开始改配置前,站长需要知道请求经过哪些缓存层、哪些 URL 会返回个人化内容,以及内容发布后允许旧页面保留多久。若这些条件还没核实,先不要为整个网站开启页面缓存。

先沿请求路径找出旧页面停在哪一层

现场排查宜从访问者一侧向应用内部推进,而不是上来就删除缓存文件。用同一个公开页面 URL,分别检查普通访问、带查询参数访问和登录后的访问;记录响应状态、Cache-Control、Age、Vary、Set-Cookie,以及现有代理或边缘服务提供的缓存状态头。

几个线索能帮助缩小范围:

  • 强制重新验证或更换浏览器后恢复正常,先检查浏览器缓存规则;但浏览器恢复正常,不代表边缘或服务器缓存也正确。
  • 边缘节点返回命中,而绕过边缘直达源站时是新内容,应检查边缘失效规则及其缓存键。
  • 源站前的页面代理连续命中旧响应,而应用直出新内容,应检查页面代理的有效期、缓存键和发布后的清理动作。
  • 应用直出仍是旧内容,应继续检查应用的对象或查询缓存,不能只清页面缓存。

测试“直达源站”时,必须保持原站点使用的主机名和协议,由有权限的运维人员在受控环境中完成;否则路由和缓存键可能改变,比较结果没有意义。涉及登录页面的测试应使用授权测试账号,不要把会话 Cookie 或令牌写入公开工单、命令记录和日志。

由页面内容决定缓存层级

页面缓存并非越靠前越好。关键是先分清缓存对象,再为每一层指定失效方式。

缓存层适合存放什么初始设置与失效重点
浏览器缓存带版本标识的静态资源;不需要即时更新的公开响应静态资源变更时更新 URL;不能指望服务器清缓存来清除访问者浏览器中的旧资源
页面代理缓存内容对未登录访问者一致的公开页面按主机名和完整请求 URI 区分;先排除会话、授权及查询参数;用有效期兜底
应用对象或查询缓存可重复使用的数据、查询结果数据变更时按对象或依赖关系失效;确认应用确实提供对应机制后再启用
边缘缓存已确认可公开、且失效链路清楚的内容缓存键、绕过规则应与源站一致;发布时同时处理边缘缓存

例如文章详情页,如果所有未登录访客看到相同正文,可以从页面代理缓存开始。账号页即使响应很快也不该作为公共页面缓存;它的正确性优先于命中率。搜索页或带筛选参数的列表页则要先确认参数是否影响内容。未经核实就忽略查询参数,可能把不同搜索结果当作同一页;把所有参数都纳入缓存键,又可能产生大量低复用的缓存条目。初次部署时,直接绕过带查询参数的请求更容易验证。

对象、查询缓存不能替代页面缓存的失效设计。如果应用改了文章数据,只清掉页面代理,而应用直出的仍是旧查询结果,页面代理下一次请求会重新缓存旧内容。因此,存在多层缓存时,发布后的清理顺序应是先确保应用数据及内部缓存已更新,再处理页面代理,最后处理边缘缓存。

在现有站点上小范围开启页面缓存

下面以已有 Nginx 反向代理、应用由本机 127.0.0.1:8080 提供响应为例。示例只针对 /articles/ 下、无 Cookie、无授权头、无查询参数的 GET 和 HEAD 请求;路径和上游地址必须按现有部署核实,不能直接照搬到整个站点。

修改前先保存当前配置,并确认实际生效的 server、location 及上游响应头。适用于已安装 Nginx、且具有配置查看权限的环境:

nginx -T

这条命令会输出完整配置,其中可能包含证书路径、上游地址等内部信息,应只在受控终端查看,不要原样公开。重点核对 /articles/ 是否会被更精确的 location 或正则规则接管,以及应用是否为页面返回 Set-Cookie、Cache-Control: private、no-store 等响应头。若文章页会按访问者身份、地理判断或请求头返回不同正文,以下公共页面缓存规则就不适用。

在现有 http {} 中加入缓存区和绕过条件;缓存目录需由实际 Nginx 工作进程具备写入权限,目录、容量及权限应按当前环境检查,勿为图省事扩大目录权限:

proxy_cache_path /var/cache/nginx/page
                 levels=1:2
                 keys_zone=page_cache:20m
                 max_size=1g
                 inactive=30m
                 use_temp_path=off;

map $request_method $skip_page_method {
    default 1;
    GET     0;
    HEAD    0;
}

map $http_cookie $skip_page_cookie {
    default 1;
    ""      0;
}

map $http_authorization $skip_page_auth {
    default 1;
    ""      0;
}

map $args $skip_page_args {
    default 1;
    ""      0;
}

map "$skip_page_method$skip_page_cookie$skip_page_auth$skip_page_args" $skip_page_cache {
    default 1;
    "0000"  0;
}

其中的缓存区大小、磁盘上限和时间只是配置示例,不是日本服务器的通用性能参数。应结合可用空间、页面数量和内容更新频率调整。inactive 表示条目在一段时间内未被访问时可被移除,不是内容更新后的主动失效通知。

然后把以下规则合并进现有站点的 server {}。如果已有 /articles/ 的 location,应在原规则上审查、合并,不要新增一个相互冲突的位置块;同时保留现有应用确实需要的代理请求头。

location /articles/ {
    proxy_pass http://127.0.0.1:8080;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;

    proxy_cache page_cache;
    proxy_cache_key "$scheme|$host|$request_uri";
    proxy_cache_methods GET HEAD;
    proxy_cache_valid 200 5m;

    proxy_cache_bypass $skip_page_cache;
    proxy_no_cache $skip_page_cache;

    add_header X-Page-Cache $upstream_cache_status always;
}

proxy_cache_bypass 防止被排除的请求读取已有缓存,proxy_no_cache 防止其响应写入缓存,两者应配合使用。缓存键包含协议、主机名和完整请求 URI,避免不同站点或不同参数的页面意外共用条目;带参数请求目前仍被绕过,保留完整 URI 是为以后逐项放开参数留下安全边界。

Nginx 默认会依据上游某些响应头决定是否缓存,例如 Set-Cookie、禁止缓存的 Cache-Control 等。因此,proxy_cache_valid 200 5m 不等于所有 200 响应都会缓存五分钟;上游给出的缓存控制也可能改变实际有效期。不要为了追求命中率直接忽略这些响应头。先查明它们由谁设置、为什么设置,再判断页面是否适合缓存。

上述操作影响 /articles/ 下匹配到该位置块的请求。上线前备份原配置文件,先在维护窗口或低风险时段验证语法,确认通过后再重载;若检查失败,不要重载。

nginx -t
nginx -s reload

这些命令适用于当前正在使用 Nginx、且执行者具有相应权限的环境。若站点通过其他服务管理方式启动 Nginx,应按实际部署方式重载,避免误操作另一套实例。

把“过期”与“发布即失效”分开设置

页面失效至少要回答两个问题:没有任何发布通知时,旧页面最多保留多久;一旦内容必须立即更新,系统怎样撤销已缓存的版本。

前一个问题由有效期兜底。示例中的五分钟适合先观察规则是否正确,并不代表所有网站都应采用这一时长。新闻、价格、库存、状态信息等内容若要求发布后立即一致,单靠定时过期并不够;后台预览与正式公开页也必须分开,预览请求不能命中公开缓存。

后一个问题要按缓存层逐层处理:

  1. 先更新数据和应用内部缓存。确认应用直出已是新正文;若应用使用对象或查询缓存,调用它实际提供的失效机制。没有对应能力时,不要假设页面代理能解决内部旧数据。
  2. 再处理页面代理。若现有环境具备经核实的按 URL 清理能力,发布时清理文章页及引用它的列表页、首页等依赖页面。不要把“清理文章详情页”误当成所有相关页面都已更新。
  3. 最后处理边缘缓存。如站点启用了边缘缓存,按其实际缓存键清理对应页面;否则边缘仍可能向访客返回旧版本。若只清边缘而源站页面代理仍旧,边缘还会再次取回旧内容。
  4. 静态资源优先换 URL。样式和脚本若使用长时间浏览器缓存,更新文件时同步改变资源 URL 或版本标识;服务器侧清理无法强制所有访问者的浏览器立刻丢弃原 URL。

需要注意,普通 Nginx 反向代理缓存配置并不自带可直接照用的按 URL 清理命令。如果没有经过验证的主动清理机制,应明确接受有效期内可能仍返回旧页;遇到必须立即停止返回旧页的情况,可临时关闭对应位置的页面缓存,验证并重载配置,让新请求回源。关闭缓存不会自动删除已存文件,恢复前还须确认旧条目已过期或已通过受支持的方法处理。不要在未核实缓存目录归属和影响范围时直接删除整个目录。

用命中、绕过和更新测试验收

配置生效后,先选一个确认公开、不会因访客而变化的文章页。在允许从测试终端访问该站点的环境中,可用以下命令查看响应头;将域名和路径替换为实际地址:

curl -sS -D - -o /dev/null 'https://example.com/articles/sample'
curl -sS -D - -o /dev/null 'https://example.com/articles/sample'
curl -sS -D - -o /dev/null 'https://example.com/articles/sample?preview=1'

首次请求通常应看到页面缓存未命中,后续相同请求才可能命中;带参数请求应绕过。实际状态还受上游响应头、已有缓存、请求是否进入该 location 等因素影响,不能只凭一次 X-Page-Cache 判断成功。接着用授权测试账号核对带 Cookie 的访问不会读取或写入公共页面缓存,并检查登录后的页面内容没有出现在未登录请求中。

验收还应做一次内容更新演练:记录旧正文,发布新正文,先检查应用直出,再按既定顺序检查页面代理与边缘返回,直到访客入口显示新内容。如果文章页已更新、列表摘要却没更新,说明失效范围漏掉了依赖页面;如果清理后又变旧,应回头检查更内层是否仍在提供旧数据。

出现异常时,按低风险顺序回查:先确认请求命中了预期的站点和 location,再看请求 Cookie、参数及上游缓存控制头,随后检查应用直出内容,最后才考虑改动缓存键或清理缓存文件。若发现个人化内容被公开命中,应立即停止受影响路径的页面缓存,验证新请求已回源,检查已缓存内容的影响范围,并按站点既定流程处理;不能仅靠等待过期。

这次部署最容易遗漏的不是 proxy_cache_valid 写了多久,而是谁能进入缓存、哪次发布会使哪些页面失效,以及关闭缓存后旧条目是否仍可能再次被使用。把这三项连同登录态、查询参数和上游响应头一起纳入每次变更检查,缓存才能在减轻源站重复工作时,不牺牲页面内容的正确性。

目录结构
全文