Skip to content

Redis

Redis 是一个高性能的内存数据存储,广泛用于缓存、会话管理、消息队列等场景。

@eggjs/redis

框架提供了 @eggjs/redis 插件来访问 Redis。该插件基于 ioredis,支持单客户端、多客户端和集群模式。

安装与配置

安装插件:

bash
npm i @eggjs/redis

开启插件:

ts
// config/plugin.ts
export default {
  redis: {
    enable: true,
    package: '@eggjs/redis',
  },
};

单客户端

ts
// config/config.default.ts
export default function () {
  return {
    redis: {
      client: {
        host: '127.0.0.1',
        port: 6379,
        password: '',
        db: 0,
      },
    },
  };
}

多客户端

ts
// config/config.default.ts
export default function () {
  return {
    redis: {
      clients: {
        cache: {
          host: '127.0.0.1',
          port: 6379,
          password: '',
          db: 0,
        },
        session: {
          host: '127.0.0.1',
          port: 6379,
          password: '',
          db: 1,
        },
      },
    },
  };
}

集群模式

ts
// config/config.default.ts
export default function () {
  return {
    redis: {
      client: {
        cluster: true,
        nodes: [
          { host: '127.0.0.1', port: 6380 },
          { host: '127.0.0.1', port: 6381 },
        ],
      },
    },
  };
}

使用方式

单客户端

ts
// app/controller/home.ts
import { Context } from 'egg';

export default class HomeController {
  async index(ctx: Context) {
    // 设置值
    await ctx.app.redis.set('foo', 'bar');

    // 获取值
    const value = await ctx.app.redis.get('foo');

    // 设置值并指定过期时间(秒)
    await ctx.app.redis.setex('temp', 60, '60秒后过期');

    // 删除键
    await ctx.app.redis.del('foo');

    ctx.body = value;
  }
}

多客户端

使用多客户端模式时,通过 app.redis.getSingletonInstance('clientName') 获取对应的客户端实例:

ts
// app/controller/home.ts
import { Context } from 'egg';

export default class HomeController {
  async index(ctx: Context) {
    const cache = ctx.app.redis.getSingletonInstance('cache');
    const session = ctx.app.redis.getSingletonInstance('session');

    await cache.set('key', 'value');
    await session.set('sid', 'session-data');

    ctx.body = await cache.get('key');
  }
}

常用命令

插件支持所有 ioredis 命令。以下是一些常用命令:

命令说明示例
set设置键值对await redis.set('key', 'value')
get获取值await redis.get('key')
setex设置值并指定过期时间(秒)await redis.setex('key', 60, 'value')
del删除键await redis.del('key')
incr自增await redis.incr('counter')
hset设置哈希字段await redis.hset('hash', 'field', 'value')
hget获取哈希字段await redis.hget('hash', 'field')
lpush从左侧推入列表await redis.lpush('list', 'value')
lpop从左侧弹出列表await redis.lpop('list')
sadd添加集合成员await redis.sadd('set', 'member')
smembers获取集合所有成员await redis.smembers('set')
zadd添加有序集合成员await redis.zadd('zset', 1, 'member')

在单元测试中使用 ioredis-mock

你可以使用 ioredis-mock 在单元测试中替代真实的 Redis 客户端,无需运行 Redis 服务器即可进行测试。

安装

bash
npm i --save-dev ioredis-mock @types/ioredis-mock

配置

ts
// config/config.unittest.ts
import RedisMock from 'ioredis-mock';
import type { EggAppInfo, PartialEggConfig } from 'egg';

export default function (_appInfo: EggAppInfo): PartialEggConfig {
  return {
    redis: {
      Redis: RedisMock,
      client: {
        host: '127.0.0.1',
        port: 6379,
        password: '',
        db: 0,
        weakDependent: true,
      },
    },
  };
}

重要:使用 ioredis-mock 时必须设置 weakDependent: true。Mock 客户端会在构造时同步触发 ready 事件,早于插件的监听器注册。如果不设置 weakDependent: true,应用启动时会挂起。

优势

  • 更快的 CI:无需启动 Redis Docker 容器
  • 更简单的本地开发:运行测试不需要 Redis 服务器
  • 隔离性:每个测试 worker 拥有独立的内存 Redis 实例
  • 兼容性:支持大部分常用 Redis 命令

注意:生产环境部署测试仍应使用真实的 Redis 服务器。

高级配置

弱依赖模式

如果你的应用可以在 Redis 未就绪时启动(例如 Redis 仅用作缓存,非关键依赖):

ts
// config/config.default.ts
export default function () {
  return {
    redis: {
      client: {
        host: '127.0.0.1',
        port: 6379,
        password: '',
        db: 0,
        weakDependent: true, // 应用启动不会等待 Redis 就绪
      },
    },
  };
}

使用 Valkey

Valkey 是 Redis 的兼容分支。可以通过 Redis 配置项使用:

ts
import Valkey from 'iovalkey';

export default function () {
  return {
    redis: {
      Redis: Valkey,
      client: {
        host: '127.0.0.1',
        port: 6379,
        password: '',
        db: 0,
      },
    },
  };
}

Born to build better enterprise frameworks and apps