在NestJS中使用cache-manager和Redis时可能会遇到的坑

WebNestJSRedisKeyvCache后端
浏览数 - 246发布于 - 2025-08-13 - 20:20

今天下午修bug时发现的问题

如果在Nest中使用了官方的缓存模块(@nestjs/cache-managercache-manager),而且使用了Redis作为具体的缓存层实现,你可能会碰到配置看起来没什么问题(没有任何报错,同时Redis连接一切正常),但是Cache没有被正常写入Redis的情况

例如下面的配置:

    CacheModule.registerAsync({
      isGlobal: true,
      imports: [ConfigModule],
      inject: [HikariConfigService],
      useFactory: async (configService: HikariConfigService) => {
        const host = configService.get('redis.host')
        const port = configService.get('redis.port')
        const password = configService.get('redis.password')
        const keyPrefix = configService.get('redis.keyPrefix')
        const database = configService.get('redis.database')

        return {
          store: [
            new KeyvAdapter(
              await redisStore({
                socket: { host, port },
                password: password || undefined,
                keyPrefix,
                database,
              }),
            ),
          ],
        }
      },
    }),

实际上,上面的这段配置是几乎没有任何问题的,除了return对象中的stores被错误地写为了store

  1. 迷惑点一:如果配置错误,包括但不限于拼写错误、没有使用Keyv作为adapter层等等,此时Nest并不会抛出任何错误来提醒你这里有问题
  2. 迷惑点二:就算配置错误,Redis也会正常连接。如果在return中正确初始化了redisStore,Redis实际上也会正常连上,如果你修改连接参数如host或者port,redisStore会因为连接不上Redis抛出异常,这会让你潜意识地认为上面的配置是没有问题的
  3. 迷惑点三:这是最难受的一点,如果CacheModule没有正确初始化redis实例,Nest会自动降级到使用内存作为缓存层,结果就是CACHE_MANAGER提供的所有方法,如getsetdel等,全部都看起来工作正常(实际上也确实工作正常,除了缓存数据存放的位置变成了内存而不是Redis),这会导致问题非常不容易被发现

弄清楚上面这几点后,相似的问题就很好解决了:

  1. @nestjs/cache-manager只会读取stores中的内容,确保stores 拼写无误,CacheModule会读取stores 数组中初始化的缓存实例,如果数组为空或者没有值,Nest会默认使用内存作为具体的缓存层
  2. stores 仅接受 Keyv 实例或 KeyvStoreAdapter。如果没有使用Keyv作为adapter层,就算stores没拼错,redisStore正常初始化,配置也会失败

最后附上文档的配置示例,文档中使用了原生的keyv包作为adapter实现

import { Module } from '@nestjs/common';
import { CacheModule } from '@nestjs/cache-manager';
import { AppController } from './app.controller';
import { createKeyv } from '@keyv/redis';
import { Keyv } from 'keyv';
import { CacheableMemory } from 'cacheable';

@Module({
  imports: [
    CacheModule.registerAsync({
      useFactory: async () => {
        return {
          stores: [
            new Keyv({
              store: new CacheableMemory({ ttl: 60000, lruSize: 5000 }),
            }),
            createKeyv('redis://localhost:6379'),
          ],
        };
      },
    }),
  ],
  controllers: [AppController],
})
export class AppModule {}

我们使用的,并且已经在生产环境中验证的相关依赖如下

import { CacheModule } from '@nestjs/cache-manager'
import { redisStore } from 'cache-manager-redis-yet'
import { KeyvAdapter } from 'cache-manager'

"@nestjs/cache-manager": "^3.0.1",
"cache-manager": "^6.4.3",
"cache-manager-redis-yet": "^5.1.5",

相关连接

Caching | NestJS - A progressive Node.js framework

https://www.npmjs.com/package/cache-manager

2 条回复

鲲

5390

#1
发布于 2025-08-14 - 01:20

yuki 棒棒!!!Sticker

ringyuki
发布于 2025-08-14 - 10:19
回复 @鲲#1

yuki 棒棒!!!!Sticker

Sticker

(。>︿<。) 已经一滴回复都不剩了哦~