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

相关推荐
H5css�海秀34 分钟前
今天是自学大模型的第一天(sanjose)
后端·python·node.js·php
SuniaWang42 分钟前
《Spring AI + 大模型全栈实战》学习手册系列 · 专题六:《Vue3 前端开发实战:打造企业级 RAG 问答界面》
java·前端·人工智能·spring boot·后端·spring·架构
韩立学长1 小时前
Springboot校园跑腿业务系统0b7amk02(程序、源码、数据库、调试部署方案及开发环境)系统界面展示及获取方式置于文档末尾,可供参考。
数据库·spring boot·后端
sheji34161 小时前
【开题答辩全过程】以 基于springboot的扶贫系统为例,包含答辩的问题和答案
java·spring boot·后端
A_nanda1 小时前
根据AI提示排查vue前端项目
前端·javascript·vue.js
代码栈上的思考2 小时前
消息队列:内存与磁盘数据中心设计与实现
后端·spring
~无忧花开~2 小时前
React状态管理完全指南
开发语言·前端·javascript·react.js·前端框架
@大迁世界3 小时前
1.什么是 ReactJS?
前端·javascript·react.js·前端框架·ecmascript
程序员小假3 小时前
我们来说一下 b+ 树与 b 树的区别
java·后端
Meepo_haha3 小时前
Spring Boot 条件注解:@ConditionalOnProperty 完全解析
java·spring boot·后端