我把51网的缓存管理拆给你看:其实一点都不玄学(别被误导)

我把51网的缓存管理拆给你看:其实一点都不玄学(别被误导)

缓存听起来很高大上、很玄学,尤其是当网站流量上去、页面老大不易更新、用户抱怨数据不对时。其实把缓存拆开来看,原则很简单:分层、分类、可控。下面把常见的缓存类型、设计思路、实战配置和坑都讲清楚,方便你直接照着在51网或类似中大型网站上落地。

一、先把缓存拆成几层来看

  • 浏览器端缓存(客户端缓存)
  • 静态资源(JS/CSS/图片)优先用长期缓存 + 文件指纹
  • HTML 页面一般短缓存或不缓存(或采用 SSR + 部分缓存)
  • CDN(全站静态加速)
  • 承担静态内容的边缘分发,命中率高能大幅减轻源站压力
  • 提供全站加速、压缩、HTTPS 协议优化
  • 反向代理缓存(例如 Nginx proxy_cache、Varnish)
  • 对业务层可控缓存,适合 Page Cache、API 响应缓存
  • 应用层缓存(内存缓存、分布式缓存如 Redis)
  • 用于热点数据、会话、模板片段等的快速读取
  • 数据库缓存与缓存穿透保护
  • 缓存空结果、使用布隆过滤器、设置合理 TTL

二、缓存策略的核心原则(三点)

  1. 分类:静态资源、可缓存页面、用户个性化页面要区分开来
  2. 可控:缓存要能被快速失效(purge)或绕过(bypass)
  3. 指标化:命中率、流量节省、响应时延是衡量标准

三、静态资源(JS/CSS/图片)实战做法

  • 使用资源指纹(hash)或版本号作为文件名:app.3a9f7.js
  • 好处:更新时直接换文件名,浏览器和 CDN 自然请求新资源,不需要复杂 purge
  • Cache-Control 配置建议:
  • 静态资源:Cache-Control: public, max-age=31536000, immutable
  • HTML(首页、文章页):Cache-Control: no-cache 或 s-maxage=60, stale-while-revalidate=30(配合 CDN)
  • ETag / Last-Modified:
  • 对于大文件或文件较少的场景,ETag 有用;指纹策略更稳健

四、反向代理缓存(以 Nginx proxy_cache 为例)

  • 场景:缓存整页 HTML 或 API(非用户个性化)可以大幅降低后端压力

  • 样例配置(简化版,放在 nginx.conf 中): proxycachepath /var/cache/nginx levels=1:2 keyszone=sitecache:100m maxsize=10g inactive=60m usetemp_path=off;

    server { … location / { proxycache sitecache; proxycachevalid 200 302 10m; proxycachevalid 404 1m; proxycachebypass $cookienocache; # 当有特定 cookie 时绕过缓存 proxynocache $cookienocache; proxycachekey "$scheme$proxyhost$requesturi$cookieuserid"; addheader X-Cache $upstreamcachestatus; proxy_pass http://backend; } }

  • 关键点解释:

  • proxycachekey 要考虑 Vary(User-Agent、Accept-Language)或 Cookie,但尽量保持 key 简洁,避免爆炸性分片

  • proxycachebypass 与 proxynocache 用于那些包含登录态或个性化内容的请求

  • add_header X-Cache 可以在调试时看到 HIT / MISS

五、动态与用户个性化内容的缓存策略

  • 做分层缓存:页面分为可缓存区块与个性化区块
  • 可缓存区块:头部、公共模块、热门推荐(可微调后端生成)
  • 个性化区块:用户头像、专属推荐(由 JS 异步拉取,或通过 AJAX/Edge Side Includes (ESI) 注入)
  • 登录态处理:
  • 登录用户的主页面可以先发一个缓存较短的 HTML(或不缓存),页面加载后通过 JS 请求缓存命中率高的 API 获取个人化数据
  • 或者使用 cookie 标记来绕过缓存(但会降低命中率)
  • ESI(Edge Side Includes):
  • 如果 CDN/反向代理支持 ESI,可把个性化小片段单独请求并拼装,既保留大内容缓存率,又实现个性化

六、缓存失效(Purge / Invalidate)策略

  • 常见手段:
  • 文件指纹:最干净的做法,更新资源时换名字,CDN 和浏览器自然请求新文件
  • API / 管理后台触发 Purge:针对页面级更新,管理系统调用 CDN/Proxy 的 purge 接口
  • 时间策略:短 TTL + stale-while-revalidate 在某些场景更稳妥
  • Purge 建议:
  • 提供管理员一键清理缓存(对具体 URL 或 Tag 级别的清理)
  • 对重要内容(首页、栏目页)需要在发布时同步触发 purge

七、常见误区与坑

  • 误区:缓存越长越好 → 会导致用户看到过时内容。用指纹替代长缓存的手动失效。
  • 误区:CDN 自动解决一切 → CDN 只能缓存你允许它缓存的内容,缓存策略和 Headers 决定一切。
  • 坑:使用 Cookie 或 Authorization header 导致缓存失效 → 记得仅对必要请求携带这些字段,静态内容应该无 Cookie。
  • 坑:不监控命中率 → 很多优化做了却没有验证,命中率、带宽节省才是最终目标。
  • 坑:缓存登录用户页面 → 除非做局部缓存或 ESI,否则会导致隐私泄露或数据混乱。

八、如何验证和监控(操作性强)

  • 调试命令:
  • curl -I https://your.site/page.html
    • 看 Cache-Control、ETag、Age、X-Cache 等头
  • curl -H "Cache-Control: no-cache" -I …
  • 使用浏览器 DevTools Network 面板,看 Size/Headers/Status(from disk cache/from memory cache)
  • 监控指标:
  • Cache Hit Ratio(边缘 + 反向代理)
  • Origin Bandwidth Saved(节省的带宽)
  • Origin Requests/sec(反向代理/后端的压力)
  • 95/99 分位响应时延(缓存命中与未命中比对)
  • 日志和报警:
  • 在 Nginx/Proxy 加上 x-cache、x-cache-key 或自定义 header,日志中统计 HIT/MISS
  • 当命中率骤降或 origin 请求激增时触发告警

九、针对51网这样内容型或技术型综合站的具体落地建议(一步步做)

  1. 静态资源立即做指纹策略并开 CDN,静态资源 Cache-Control max-age=1年
  2. 首页/频道页采用边缘缓存(CDN)+ 反向代理缓存(Nginx),s-maxage=60s + stale-while-revalidate=30s
  3. 对于用户个性化区域,用异步请求加载或 ESI 注入,避免主页面缓存被污染
  4. 实现清晰的 purge 流程:文章发布/更新时后台自动调用 CDN+反向代理的 purge API
  5. 打点监控:把 x-cache 状态和响应 time 落到监控系统,设置 HIT/MISS 报表并定期评审
  6. 做压测:模拟 purge 后的高并发回源场景,确定后端承载能力并做预案(rate limit、降级逻辑)

十、举个小例子:文章更新后的缓存流程

  • 发布文章(A)
  • 后端写库并推送静态化任务(如果有静态化)
  • 后端触发 CDN/Proxy 的 purge(目标是首页、栏目页、该文章 URL)
  • 如果使用指纹资源,文章内引用的 JS/CSS 不需 purge
  • 用户访问:首次访问可能 MISS,随后 HIT 并在 CDN/Proxy 中保鲜

十一、收尾与实践建议

  • 建议先从“最痛点”入手:哪里源站最吃力,就先缓存哪里(例如首页/频道/热门文档)
  • 做小而可测的改动:改 header、观察 24-48 小时的命中率与回源情况,再扩大推广
  • 文档化 purge 流程与权限控制,避免误清全站缓存导致缓存雪崩