Next.js 开箱即用的功能

  • Data cache (数据缓存) – 在 Next.js 13+ 中,每个 fetch() 调用都会进入请求级的内存缓存。添加 revalidate 选项可以告诉运行时在设定的时间间隔后刷新数据,从而仅在需要时才将“热” API 调用转变为“冷”调用。
  • Full-route cache (全路由缓存) – 框架会持久化渲染后的 HTML 以及整个路由所需的数据。回头客会看到即时的页面转换,因为服务器跳过了重新渲染的过程。
  • ISR (增量静态再生) – 静态页面在后台重新生成,而旧版本继续提供服务。这让你能够保持大型网站的静态特性,而无需在每次内容更改时都进行完整的重新构建。
  • Server Component cache() – React 的 cache 辅助函数会在单个请求的持续时间内对昂贵的计算或数据库连接进行记忆化(memoization),从而避免在页面组件树内部进行重复工作。

这些缓存解决了“首次访问”问题,但它们仍然运行在 Node 进程内部。为了保护服务器和数据库,需要将缓存层向外推。

你可以添加的外部层

存储内容 典型工具 作用
CDN 静态资源、HTML、API JSON Cloudflare, Akamai, AWS CloudFront 将内容移动到边缘节点,缩短用户访问的往返时间
Reverse proxy (反向代理) 在到达 Node 之前的完整页面响应 Nginx, Varnish 直接提供缓存页面,减轻 Next.js 实例的负载
Application-level cache (应用级缓存) 昂贵的数据库查询或 API 调用的结果 Redis, Memcached 提供快速的键值存储,在服务器重启后依然存在,并可在多个应用实例之间共享

每一层都比源数据库更远,因此某一层的缓存未命中(miss)会级联到下一层,最终只有在绝对必要时才会到达数据库。

保持缓存的新鲜度

缓存失效(Invalidation)是让大多数团队感到头疼的问题。以下三种实用模式效果很好:

  • 基于时间 (TTL) – 为缓存条目分配固定的过期时间。配置简单,但在计时器到期前可能会提供过时的数据。
  • 事件驱动 – 接入你的 CMS 或任何在内容更改时发送 Webhook 的数据源。Webhook 会触发相关缓存条目的清除。
  • 基于标签 – 为一组 fetch 请求附加一个逻辑标签(例如 product-list)。当该组中的任何项目发生变化时,只需调用一次 revalidateTag('product-list') 即可清除所有共享该标签的条目。

混合使用这些方法可以让你在数据新鲜度和缓存命中率之间取得平衡。

适用于大多数团队的分层架构

  1. Browser cache (浏览器缓存) – 静态资源(CSS、JS、图像)设置较长的 max-age,这样用户的设备就无需再次请求网络。
  2. CDN – 边缘节点缓存完整的 HTML 页面和 API JSON,并遵循你在 Next.js 中设置的 Cache-Control 响应头。
  3. Reverse proxy (反向代理) – Nginx 或 Varnish 实例位于 Next.js 服务器前端,为很少变化的路由提供缓存响应。
  4. Next.js internal cache (Next.js 内部缓存) – 框架的数据缓存和路由缓存处理请求级的记忆化和 ISR。
  5. Application cache (应用缓存) – Redis 存储重型数据库查询的结果,并以查询参数或标签作为键(key)。
  6. Database (数据库) – 最终的事实来源(source of truth),仅在所有更高层级的缓存都未命中时才进行查询。

当请求到达时,它会沿着这个列表向下查找,直到某一层给出响应。最快的响应获胜,并且响应会向上回写到整个链条中,以供后续命中。

整合方案

  1. 在 API 路由中设置 Cache-Control 响应头
  2. 配置你的 CDN – 为 HTML 和 JSON 端点启用边缘缓存,并确保 CDN 遵循 Cache-Control
  3. 部署反向代理 – 在 Next.js 服务器前部署 Nginx。
  4. 添加 Redis – 缓存昂贵的数据库查询结果。
  5. 在组件中使用 revalidateTag – 调用 revalidateTag 来清除特定标签的 Next.js 内部缓存。

总结

Next.js 内部的单一缓存可以加速首次请求,但真正的可扩展性来自于一套严谨的技术栈:浏览器 → CDN → 反向代理 → 框架 → Redis → 数据库。配置好每一层,通过时间、事件和标签来处理缓存失效,并密切关注你的性能指标。这样在后端应对流量激增时,延迟仍能保持在较低水平。