🚀 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 缓存无效"的坑!

相关推荐
开发者每周简报几秒前
网海三部曲·无名宗师传
javascript·人工智能
卷毛的技术笔记15 分钟前
告别硬编码!Spring AI Alibaba 实现 AI Agent 智能工具调用(Tool Calling)
java·人工智能·后端·python·spring·ai编程
会编程的土豆28 分钟前
Go 语言反射(Reflection)详解
开发语言·后端·golang
喵个咪1 小时前
GoWind Toolkit Go后端代码生成 完整全流程实战
后端·go·orm
basketball6161 小时前
Go 语言从入门到进阶:4. 数组和MAP使用方法总结
开发语言·后端·golang
qq_2518364571 小时前
SpringBoot+Vue 共享电池柜管理系统 完整实现 前后端分离项目实战 完整代码
vue.js·spring boot·后端
zhangxingchao2 小时前
AI 大模型核心六:量化、Workflow 与 Agent、多轮 RAG
前端·人工智能·后端
之歆2 小时前
Day01_ES6+ 专业指南:从基础到实战的现代JavaScript开发(下)
前端·javascript·es6
IT_陈寒3 小时前
Vite打包时遇到的坑,原来问题出在这里
前端·人工智能·后端
kyriewen3 小时前
AI生成代码快如闪电,但我修了三个小时——它到底帮了谁?
前端·javascript·ai编程