发布于 2026-02-16
使用 unstable_cache + revalidateTag 组合实现 Next.js 服务端函数缓存,并结合 Redis 广播,在多实例部署中实现缓存一致性。
https://nextjs.org/docs/app/api-reference/functions/unstable_cache
适合服务端数据读取,如直接读数据库或聚合多源数据的服务端函数,配合 tags 与 revalidate 实现自动失效与定时刷新。
典型结构:
return unstable_cache(
async () => getPublicPostList(input),
['public-post-list', String(input.page), String(input.count), String(version)],
{ revalidate: 300, tags: ['public-posts'] },
)();
关键点:
https://nextjs.org/docs/app/api-reference/functions/revalidateTag
当写入数据后主动失效缓存。
写入数据后触发,如:
还有一种常见的缓存用法是 fetch 级别缓存与刷新:
fetch 的 cache/next.revalidate 控制await fetch(url, { cache: 'force-cache' });
await fetch(url, { cache: 'no-store' });
await fetch(url, { next: { revalidate: 300, tags: ['posts'] } });
fetch 缓存失效:
import { revalidatePath } from 'next/cache';
revalidatePath('/posts');
项目采用了 unstable_cache + revalidateTag 来管理缓存。使用 pm2 多实例部署后,有一个问题,每个实例 revalidateTag 只能影响自己本身,缓存刷新不一致。
采用 Redis 广播的方式,多实例部署时,确保 unstable_cache 的 tag 失效可以同步到所有实例。
next:tagver:<tag>)revalidateTag,同时写入版本号并广播到 Redis发布者示例:
import { createClient } from 'redis';
const client = createClient({ url: process.env.REDIS_URL });
await client.connect();
await client.publish('events', JSON.stringify({ type: 'POST_UPDATED', id: 1 }));
订阅者示例:
import { createClient } from 'redis';
const client = createClient({ url: process.env.REDIS_URL });
await client.connect();
await client.subscribe('events', (message) => {
const payload = JSON.parse(message);
console.log('收到事件', payload);
});
ensureRevalidateSubscriber() 启动订阅getCacheTagVersion(tag) 读本地或 Redis 版本号unstable_cache key示例(文章列表):
ensureRevalidateSubscriber();
const version = await getCacheTagVersion(PUBLIC_POST_TAG);
return unstable_cache(
async () => getPublicPostList(input),
['public-post-list', String(input.page), String(input.count), String(version)],
{ revalidate: 300, tags: [PUBLIC_POST_TAG] },
)();
revalidateTags([tag...])revalidateTagREDIS_URL 时只在本实例失效,版本号走内存 Mapservices 层,避免组件直接操作revalidateTags,不要在组件/Action 里直接 revalidateTag