NextJS 13缓存失效与PM2集群多实例技术咨询
Next.js 13 Server Components 缓存机制与集群模式缓存失效方案
Next.js 13 Server Components 缓存工作机制
Next.js 13的Server Components缓存主要分两类:
- 静态数据缓存:Server Components里用
fetch拉取的静态数据,默认会存在磁盘的.next/cache目录里,属于持久化缓存,默认有效期30天,也能通过revalidate参数自定义过期时间。 - 动态数据缓存:如果
fetch设置了cache: 'no-store'或revalidate: 0,数据不会被缓存;用默认的cache: 'force-cache'或指定revalidate值时,会同时用到内存缓存和磁盘缓存。另外还支持标签缓存,可以给缓存数据打标签,后续通过标签批量失效缓存。
是否属于进程本地缓存?
不全是:
- 磁盘缓存(
.next/cache)是实例共享的,因为存在文件系统里,只要所有PM2实例挂载同一个目录就能访问到。 - 内存缓存是进程本地的,每个PM2实例都会维护自己的内存缓存副本,这部分不会在实例间共享。
PM2集群模式下批量清除所有实例的缓存标签方案
因为内存缓存是进程本地的,得让每个实例都收到缓存失效的指令,这里给几个实用方法:
方法1:通过PM2进程间通信(IPC)触发
PM2支持集群模式下的进程广播,你可以在Webhook服务里调用PM2 API,给所有集群实例发缓存失效消息:
- 在Next.js应用里加个IPC监听逻辑,比如在自定义服务器文件(
server.js)或中间件里,监听特定消息(比如'clear-cache-tags'),收到后调用revalidateTag()清除对应标签的缓存。 - Webhook后端用
pm2.broadcast()方法,把要清除的标签列表发给所有实例。
示例代码(Next.js端):
// 自定义server.js文件 const { createServer } = require('http'); const { parse } = require('url'); const next = require('next'); const dev = process.env.NODE_ENV !== 'production'; const app = next({ dev }); const handle = app.getRequestHandler(); app.prepare().then(() => { createServer(async (req, res) => { try { const parsedUrl = parse(req.url, true); await handle(req, res, parsedUrl); } catch (err) { console.error('处理请求出错', req.url, err); res.statusCode = 500; res.end('内部服务器错误'); } }).listen(3000, (err) => { if (err) throw err; console.log('> 服务启动完成:http://localhost:3000'); }); // 监听PM2的IPC消息 process.on('message', (message) => { if (message.type === 'clear-cache-tags') { const { tags } = message; tags.forEach(tag => { app.revalidateTag(tag); console.log(`进程${process.pid}已清除缓存标签:${tag}`); }); } }); });
Webhook端调用PM2广播的示例:
const pm2 = require('pm2'); pm2.connect((err) => { if (err) { console.error(err); process.exit(2); } // 向所有集群实例广播缓存失效指令 pm2.broadcast({ type: 'clear-cache-tags', tags: ['product-data', 'user-profile'] }, (err) => { pm2.disconnect(); if (err) throw err; }); });
方法2:用共享存储触发(比如Redis)
借助Redis这类共享存储,让所有实例订阅缓存失效事件:
- 每个Next.js实例启动一个Redis订阅客户端,监听特定频道(比如
nextjs-cache-invalidation)。 - Webhook后端需要失效缓存时,向Redis频道发布带要清除标签的消息。
- 每个实例收到消息后,调用
revalidateTag()清除对应标签的缓存。
这种方法不依赖PM2的IPC,更适合跨服务器部署的场景。
方法3:重启PM2实例(不推荐)
如果缓存失效频率极低,可以通过Webhook调用pm2 reload <app-name>重启所有实例。但这种方法会导致服务短暂中断,影响用户体验,只适合极端场景。
内容的提问来源于stack exchange,提问作者Johan Nordberg
相关产品推荐
相关产品推荐

