🚀 NestJS 使用 cache-manager-redis-store 缓存无效?真相在这里!

在 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 缓存真正生效,我们需要做两件事:

  1. 手动创建 Keyv 实例;
  2. 解决 cache-manager-redis-storeKeyv 方法名不兼容的问题。

下面是正确的配置:

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 补齐 deleteclear 方法
推荐替代方案 使用 @keyv/redis 官方适配器

如果你的项目中出现了"缓存无效"或"Node 堆内存暴涨"的问题,很可能就是这个配置未生效导致的。

希望这篇文章能帮你彻底理清 NestJS 缓存体系的变化,避开"Redis 缓存无效"的坑!

相关推荐
SimonKing3 小时前
【开发者必备】Spring Boot 2.7.x:WebMvcConfigurer配置手册来了(一)!
java·后端·程序员
oak隔壁找我3 小时前
Java Collection 包使用指南
java·后端
皮皮虾我们跑3 小时前
前端HTML常用基础标
前端·javascript·html
卓码软件测评3 小时前
第三方CMA软件测试机构:页面JavaScript动态渲染生成内容对网站SEO的影响
开发语言·前端·javascript·ecmascript
Mintopia4 小时前
📚 Next.js 分页 & 模糊搜索:在无限数据海里优雅地翻页
前端·javascript·全栈
Mintopia4 小时前
⚖️ AIGC版权确权技术:Web内容的AI生成标识与法律适配
前端·javascript·aigc
oak隔壁找我4 小时前
Spring Boot MongoDB 使用技巧
java·后端
倚栏听风雨4 小时前
RAG检索增强生成(Retrieval Augmented Generation)
后端