在 NestJS 项目中,我们经常会用到缓存机制来减少数据库访问、提升接口性能。而在使用 Redis 作为缓存存储时,大多数教程都会推荐 cache-manager-redis-store
。
不过,如果你使用了 NestJS v10+ 搭配 cache-manager-redis-store@3.x ,可能会发现 ------
Redis 根本没存入数据!缓存仍然落在内存中,甚至可能引发 堆内存溢出!😱
🧩 一、常见错误写法
很多文章(包括一些 AI 工具生成的示例)给出的配置通常是这样的:
ts
import { Module } from '@nestjs/common';
import { CacheModule } from '@nestjs/cache-manager';
import { redisStore } from 'cache-manager-redis-store';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [
CacheModule.registerAsync({
useFactory: async () => ({
store: await redisStore({
socket: {
host: 'localhost',
port: 6379,
},
}),
}),
isGlobal: true,
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
这段代码表面上看没问题,store
字段也确实是 Redis store 实例,但实际上它不会生效 。
验证方式很简单:运行后在 Redis 中查看键值,根本找不到缓存内容。
🧨 二、为什么配置没生效?
问题的关键在于 CacheModule.registerAsync()
的类型定义。
从 NestJS v10 开始,@nestjs/cache-manager
内部基于 Keyv 重新封装了缓存逻辑。
useFactory
返回的配置项类型为 CacheManagerOptions
,其定义如下:
ts
import { CreateCacheOptions } from 'cache-manager';
import { Keyv, KeyvStoreAdapter } from 'keyv';
/**
* Interface defining Cache Manager configuration options.
*
* @publicApi
*/
export interface CacheManagerOptions extends Omit<CreateCacheOptions, 'stores'> {
/**
* Cache storage manager. Default is `'memory'` (in-memory store). See
* [Different stores](https://docs.nestjs.com/techniques/caching#different-stores)
* for more info.
*/
stores?: Keyv | KeyvStoreAdapter | (Keyv | KeyvStoreAdapter)[];
/**
* Cache storage namespace, default is `keyv`.
* This is a global configuration that applies to all `KeyvStoreAdapter` instances.
*/
namespace?: string;
/**
* Default time to live in milliseconds.
* This is the maximum duration an item can remain in the cache before being removed.
*/
ttl?: number;
/**
* Optional. If refreshThreshold is set, the TTL will be checked after retrieving a value from the cache.
* If the remaining TTL is less than the refreshThreshold, the system will update the value asynchronously.
*/
refreshThreshold?: number;
/**
* Default is false.
* If set to true, the system will not block when using multiple stores.
* For more information on how this affects function types, visit [documentation](https://www.npmjs.com/package/cache-manager#options).
*/
nonBlocking?: boolean;
}
可以看到,它不再直接接受 store
字段,而是使用 stores ,且要求传入 Keyv 兼容的存储适配器 。
而 cache-manager-redis-store
返回的对象并不符合 Keyv
的接口规范,因此 NestJS 会回退到默认内存缓存。
🧰 三、正确的配置方式
要让 Redis 缓存真正生效,我们需要做两件事:
- 手动创建
Keyv
实例; - 解决
cache-manager-redis-store
和Keyv
方法名不兼容的问题。
下面是正确的配置:
ts
import { Module } from '@nestjs/common';
import { CacheModule } from '@nestjs/cache-manager';
import { redisStore } from 'cache-manager-redis-store';
import { Keyv } from 'keyv';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [
CacheModule.registerAsync({
useFactory: async () => {
const store = await redisStore({
host: 'localhost',
port: 6379,
});
// 解决与 Keyv 之间的方法名称兼容性问题
Object.defineProperties(store, {
delete: {
value: store.del,
},
clear: {
value: store.reset,
},
});
return {
stores: new Keyv({ store, namespace: '' }),
};
},
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
✅ 如此配置后,NestJS 的 CacheModule 才会真正使用 Redis 存储。
此时你在 Redis CLI 中执行 keys *
,即可看到缓存键值。
💡 四、更推荐的方式:使用官方适配器
虽然通过上面的方式可以让 cache-manager-redis-store
正常工作,但由于它与 Keyv 体系存在兼容性问题,不推荐长期使用。
👉 更建议使用 @keyv/redis
官方适配器:
bash
npm i @keyv/redis
配置更简洁:
ts
import { Module } from '@nestjs/common';
import { CacheModule } from '@nestjs/cache-manager';
import { AppController } from './app.controller';
import { createKeyv } from '@keyv/redis';
import { CacheableMemory } from 'cacheable';
@Module({
imports: [
CacheModule.registerAsync({
useFactory: () => {
return {
stores: createKeyv('redis://localhost:6379'),
};
},
}),
],
controllers: [AppController],
})
export class AppModule {}
这样可以完全规避兼容性问题,稳定可靠。
✅ 五、总结
项目 | 说明 |
---|---|
问题来源 | NestJS v10 改为基于 Keyv 的缓存体系 |
错误写法 | store: await redisStore(...) |
正确写法 | stores: new Keyv({ store }) |
兼容性修复 | 给 store 补齐 delete 、clear 方法 |
推荐替代方案 | 使用 @keyv/redis 官方适配器 |
✨
如果你的项目中出现了"缓存无效"或"Node 堆内存暴涨"的问题,很可能就是这个配置未生效导致的。
希望这篇文章能帮你彻底理清 NestJS 缓存体系的变化,避开"Redis 缓存无效"的坑!