独立站缓存策略:页面缓存、对象缓存、浏览器缓存的配置
一、三层缓存各自管什么
独立站的缓存可以分三层,每层解决不同的问题,不要混为一谈。页面缓存把整个HTML渲染结果存成静态文件,下次有人访问同一个URL直接返回文件,不用再跑PHP和数据库。对象缓存把数据库查询的结果存到内存(如Redis或Memcached),下次同样的查询直接从内存拿,不用再查MySQL。浏览器缓存用HTTP响应头告诉访客的浏览器”这个文件你本地存着”,下次访问直接从本地磁盘读。
三层的性能收益差别很大。页面缓存收益最大——它把PHP执行和数据库查询整个跳过,LCP能从4秒以上降到1秒以内。对象缓存收益中等——它只省掉数据库查询时间,页面缓存已经命中的话,对象缓存根本不会被触发。浏览器缓存收益针对回访访客——第一次访问必须下载,第二次起本地读,回访速度提升明显。
| 缓存层 | 存什么 | 存在哪里 | 性能收益 | 典型工具 |
|---|---|---|---|---|
| 页面缓存 | 完整HTML页面 | 服务器磁盘或内存 | 最大,LCP降60%至80% | WP Rocket、LiteSpeed Cache |
| 对象缓存 | 数据库查询结果、PHP对象 | Redis或Memcached | 中等,DB查询时间降50% | Redis、Memcached |
| 浏览器缓存 | CSS/JS/图片 | 访客浏览器本地 | 回访访客,二次访问快 | Cache-Control响应头 |
| CDN缓存 | 静态资源+部分HTML | 全球边缘节点 | 跨地域延迟降50%以上 | Cloudflare、Akamai |
很多人一上来就折腾Redis和Memcached,其实对B2B独立站来说,配好页面缓存已经解决了80%的性能问题。对象缓存是加分项,适合月UV超过5万或数据库查询变慢的时候再上。CDN和三层缓存的关系见CDN全球加速与节点选择,性能指标的合格线见Core Web Vitals优化。
二、页面缓存:HTML怎么存才不出错
页面缓存是最值钱的一层,也是最容易配错的一层。配错的典型症状是:访客提交询盘后,看到的是上一个访客的提交内容;或者用户登录后看到的还是未登录状态的页面。原因是页面缓存把带动态内容的HTML也存成了静态文件。
正确的做法是按URL和用户状态分两类:公开静态页面(首页、产品页、博客文章页)走页面缓存;动态页面(询盘表单提交后、wp-admin后台、登录后页面、购物车)必须跳过缓存。WordPress的缓存插件(WP Rocket、LiteSpeed Cache)都支持”排除URL”和”按Cookie跳过缓存”的规则。
| 页面类型 | 是否缓存 | 缓存时间 | 排除规则 |
|---|---|---|---|
| 首页、产品列表页 | 缓存 | 1小时至4小时 | 登录用户排除 |
| 博客文章页 | 缓存 | 12小时至1天 | 内容更新时手动刷新 |
| 询盘表单页 | 不缓存 | 不设 | 永远回源 |
| 表单提交成功页 | 不缓存 | 不设 | 带session cookie |
| wp-admin后台 | 不缓存 | 不设 | 管理员cookie排除 |
| 搜索结果页 | 短缓存或不缓存 | 5分钟 | 避免缓存不同搜索词 |
场景示例:一个工业装备官网的产品详情页,URL是 /products/cnc-machine-a/,这个页面内容几个月才改一次,完全可以缓存1天。但询盘表单的”提交成功”页面URL是 /inquiry-thank-you/,这个页面每个访客看到的内容应该是自己提交的确认信息,绝对不能缓存。在WP Rocket里,把 /inquiry-thank-you/ 和 /wp-admin/* 加到Never Cache URL(s)列表里。
缓存失效也是页面缓存的关键。改了一篇博客文章,怎么让线上立刻生效?两种方式:一种是发布时手动Purge全部缓存,另一种是用”按URL刷新”只清那一篇。WP Rocket在文章更新时会自动刷新相关缓存,但很多自定义页面不会自动触发,需要养成发布后点一下Purge的习惯。环形山在出海站里把缓存失效和发布流程绑定,详见环形山技术栈与四个自研插件。
三、对象缓存:数据库查询结果怎么复用
页面缓存命中的时候,PHP和数据库都不会跑,对象缓存自然也用不上。但当页面缓存没命中时——比如你刚发布了一篇新文章、或者访问了一个不该缓存的动态页面——PHP就要查数据库了。一个WordPress页面平均要查12至20次数据库,每次查询都走磁盘IO,慢查询累积起来就能让页面耗时超过1秒。
对象缓存把这些查询结果存到Redis或Memcached里,下次同样的查询直接从内存读。Redis在单台服务器上装一下,WordPress用Redis Object Cache插件接入,不需要改任何代码。配置正确的话,数据库查询时间能降50%以上,页面缓存miss时的响应时间也能从1.5秒降到0.5秒以内。
| 指标 | 无对象缓存 | 有Redis对象缓存 | 提升幅度 |
|---|---|---|---|
| 页面数据库查询次数 | 12至20次/页 | 2至5次/页 | 减少70%至80% |
| 单次查询耗时 | 5至20毫秒(磁盘IO) | 0.1至1毫秒(内存) | 快10至50倍 |
| 页面缓存miss时响应时间 | 1至1.5秒 | 0.3至0.5秒 | 降50%以上 |
| MySQL CPU占用 | 高峰80%以上 | 高峰30%至40% | 降一半以上 |
对象缓存不是必须上的。月UV在1万以下的B2B站,数据库压力不大,页面缓存已经扛住了95%的请求,上Redis的收益不明显。什么时候该上?两个信号:一是MySQL慢查询日志里每天有超过100条查询超过1秒;二是后台编辑文章时,保存后前台要等好几分钟才生效(对象缓存没正确失效)。数据库慢查询和索引优化见独立站数据库慢查询与索引优化。
四、浏览器缓存:静态资源的缓存头怎么设
浏览器缓存是三层里最容易配置的一层,它不涉及服务器端任何程序,只要在Web服务器(Nginx或Apache)加几行响应头就行。原理是:服务器在返回CSS、JS、图片时,在HTTP响应头里加Cache-Control: max-age=2592000,告诉浏览器”这个文件你本地存30天”,30天内再访问就不请求服务器了。
但这里有一个经典矛盾:浏览器缓存时间设长了,用户访问很快;但你改了CSS或JS,用户本地还是旧版本,看到的页面样式不对。解决方法不是把缓存时间设短,而是给文件名加版本号或hash——比如 style.css?v=2 或 style.abc123.css,文件内容变了,URL就变了,浏览器自动重新下载。
| 资源类型 | Cache-Control建议 | max-age | 更新策略 |
|---|---|---|---|
| 图片(jpg/png/webp) | public, max-age=31536000 | 1年 | 文件名带hash,换图即换名 |
| 字体文件 | public, max-age=31536000 | 1年 | 字体不变不用改 |
| CSS样式表 | public, max-age=604800 | 7天 | 文件名带版本号?ver=2 |
| JavaScript | public, max-age=604800 | 7天 | 文件名带版本号?ver=2 |
| HTML页面 | no-cache, must-revalidate | 不缓存 | 每次回源验证 |
| favicon.ico | public, max-age=604800 | 7天 | 很少改 |
反直觉判断:很多人怕缓存时间长了改内容用户看不到,于是把所有资源的max-age都设成1小时。结果是每个访客每次访问都重新下载全部CSS和JS,首屏时间反而变慢。正确做法是大胆设长(图片1年、CSS/JS 7天),但用文件hash或版本号解决更新问题。WordPress的wp_enqueue_script函数自动加版本号,主题和插件更新时版本号会自动变,不需要手动管。
图片优化和媒体资产治理见媒体资产治理与图片压缩。多语言站的静态资源缓存还要注意hreflang和CDN缓存的交互,见Hreflang多语言落地。
五、缓存失效策略与常见冲突
缓存配好之后,最大的问题是”怎么让缓存该过期的时候过期”。缓存没及时失效,用户看到旧内容;缓存太容易失效,性能收益又没了。独立站常见的缓存失效场景有四个:发布新文章、更新产品信息、修改CSS/JS、提交询盘表单。每个场景对应不同的失效策略。
| 场景 | 失效范围 | 失效方式 | 注意事项 |
|---|---|---|---|
| 发布新博客文章 | 首页+文章列表+单篇 | WP Rocket自动刷新 | 分类页和标签页也要刷新 |
| 更新产品价格 | 产品详情页+列表页 | 手动Purge对应URL | 不要Purge全部,影响性能 |
| 改CSS/JS | 对应静态文件 | 改版本号自动生效 | 不要改max-age,改文件名 |
| 提交询盘表单 | 表单页永不缓存 | URL排除规则 | 成功页也不能缓存 |
| 全站改版 | 全部缓存 | 一键Purge All | 选在低峰期做 |
| 更新插件/主题 | 全部缓存 | 自动或手动Purge | 更新前先备份 |
常见冲突有两个:一是装了两个缓存插件(比如同时装WP Rocket和LiteSpeed Cache),两个插件都在改.htaccess和输出缓冲,结果页面白屏或样式错乱。规则是全站只装一个缓存插件。二是页面缓存和登录状态冲突——用户登录了后台,前台还是缓存的未登录页面,看到的导航栏不对。解决方法是缓存插件识别登录cookie后自动跳过缓存。
缓存策略上线后要持续监控,每月检查一次缓存命中率和LCP。缓存命中率突然下降,通常是有人改了URL结构或加了带随机参数的链接。监控和告警清单见站点监控与告警,日常维护事项见官网维护期每月六件事。备份和恢复演练也要在缓存配置变更后做一次,见网站备份与恢复演练。
FAQ 常见问题
WordPress独立站必须装缓存插件吗?
询盘表单页能不能缓存?
Redis对象缓存什么时候该上?
浏览器缓存时间设多久合适?
缓存改了内容用户看不到怎么办?
页面缓存和CDN缓存会不会冲突?
写在最后
缓存这件事,新手最容易走两个极端:要么完全不配,每个页面都现跑PHP和数据库,首屏4秒以上;要么配得太激进,把表单页也缓存了,结果用户看到别人的提交内容。正确的思路是”分层处理”——静态页面大胆缓存,动态页面坚决不缓存,静态资源长缓存加版本号。
落地三步:第一步,装一个页面缓存插件(WP Rocket或LiteSpeed Cache二选一),把表单页和wp-admin排除;第二步,配Nginx的Cache-Control头,图片1年、CSS/JS 7天、HTML不缓存;第三步,月UV超过5万时再上Redis对象缓存。这三步做完,LCP基本能压到1秒以内,而且不会出现缓存串内容的事故。
一句可以记住的话:缓存是独立站性能的杠杆——页面缓存省80%时间,对象缓存省数据库,浏览器缓存省回访,三层各管一段,别让表单页进了缓存。
