从 ioredis 迁移

了解 ioredisnode-redis 之间的区别。

Redis 之前推荐使用 ioredis 客户端库进行 Node.js 开发,但该库现已弃用,推荐使用 node-redis。本指南概述了这两个库之间的主要异同。如果您是 ioredis 用户,并且想启动新的 Node.js 项目或将现有的 ioredis 项目迁移到 node-redis,您可能会发现此信息很有用。

ioredisnode-redis 对比

下表总结了 ioredisnode-redis 如何实现 Redis 的一些关键特性。有关每个特性的更多信息,请参阅以下部分。

连接

特性 ioredis node-redis
初始化连接 在创建客户端实例时发生 需要您在客户端实例上调用一个方法
连接丢失后重新连接 默认为自动 默认为手动
连接事件 发出 connectreadyerrorclose 事件 发出 connectreadyerrorendreconnecting 事件

命令处理

特性 ioredis node-redis
命令大小写 仅小写(例如 hset 大写或驼峰式大小写(例如 HSEThSet
命令参数处理 参数对象展平并直接传递各项 解析参数对象以生成正确的参数列表
异步命令结果处理 回调和 Promises 仅支持 Promises
执行任意命令 使用 call() 方法 使用 sendCommand() 方法

技巧

特性 ioredis node-redis
管道 自动,或使用 pipeline() 命令 自动,或使用 multi() 命令
Scan 迭代 使用 scanStream() 使用 scanIterator()
订阅频道 使用客户端对象的 client.on('message', ...) 事件 使用 subscribe(...) 命令

特定命令

命令 ioredis node-redis
SETNX 显式支持 作为 SET 命令的一个选项支持
HMSET 显式支持 支持标准 HSET 功能
CONFIG 显式支持 支持单独的 configGet(), configSet() 等方法

详细信息

以下部分更详细地解释了 ioredisnode-redis 之间的对比要点。

初始化连接

当您创建客户端对象实例时,ioredis 会连接到 Redis 服务器

const client = require('ioredis');

// Connects to localhost:6379 on instantiation.
const client = new Redis();

node-redis 要求您在客户端对象上调用 connect() 方法以建立连接

import { createClient } from 'redis';

const client = await createClient();
await client.connect(); // Requires explicit connection.

连接丢失后重新连接

如果连接因错误丢失,ioredis 会自动尝试重新连接。默认情况下,node-redis 不会尝试重新连接,但您可以在创建客户端对象时启用自定义重新连接策略。更多信息请参阅连接断开后重新连接

连接事件

ioredis 发出的 connectreadyerrorclose 事件等同于 node-redis 中的 connectreadyerrorend 事件,但 node-redis 还会发出 reconnecting 事件。更多信息请参阅连接事件

命令大小写

ioredis 中的命令方法始终是小写。使用 node-redis 时,您可以使用方法名称的大写或驼峰式版本。

// ioredis
client.hset('key', 'field', 'value');

// node-redis
client.HSET('key', 'field', 'value');

// ...or
client.hSet('key', 'field', 'value');

命令参数处理

ioredis 将命令参数解析为字符串,然后将其传递给服务器,类似于 redis-cli 的方式。

// Equivalent to the command line `SET key 100 EX 10`.
client.set('key', 100, 'EX', 10);

作为参数传递的数组会被展平为单个元素,对象会被展平为顺序的键值对

// These commands are all equivalent.
client.hset('user' {
    name: 'Bob',
    age: 20,
    description: 'I am a programmer',
});

client.hset('user', ['name', 'Bob', 'age', 20, 'description', 'I am a programmer']);

client.hset('user', 'name', 'Bob', 'age', 20, 'description', 'I am a programmer');

node-redis 对命令参数使用预定义格式。其中包括用于命令选项的特定类,这些类通常与 CLI 命令的语法不对应。在内部,node-redis 使用您传递的方法参数构建正确的命令。

// Equivalent to the command line `SET bike:5 bike EX 10`.
client.set('bike:5', 'bike', {EX: 10});

异步命令结果处理

ioredisnode-redis 的所有命令都异步执行。ioredis 支持回调和 Promise 返回值来响应命令结果

// Callback
client.get('mykey', (err, result) => {
  if (err) {
    console.error(err);
  } else {
    console.log(result);
  }
});

// Promise
client.get('mykey').then(
    (result) => {
        console.log(result);
    },
    (err) => {
        console.error(err);
    }
);

node-redis 仅支持 Promise 对象作为结果,因此您必须始终使用 then() 处理程序或 await 操作符来接收它们。

执行任意命令

ioredis 允许您使用 call() 命令,以类似于 redis-cli 的格式发出任意命令

await client.call('JSON.SET', 'doc', "$", '{"f1": {"a":1}, "f2":{"a":2}}');

node-redis 中,您可以在事务外部使用 sendCommand() 实现相同的效果

await client.sendCommand(['hset', 'hash2', 'number', '3']);

在事务中,使用 addCommand() 包含任意命令。请注意,您可以在同一事务中自由混合使用 addCommand() 调用和标准命令

const responses = await client.multi()
  .addCommand(['hset', 'hash3', 'number', '4'])
  .hGet('hash3', 'number')
  .exec();

管道

如果 ioredisnode-redis 在同一个事件循环的“tick”中执行命令,它们都会自动进行管道化(更多信息请参阅执行管道)。

您也可以在两个客户端中创建包含显式命令的管道。使用 ioredis,您可以使用 pipeline() 命令链式调用一系列命令,最后使用 exec() 运行管道

// ioredis example
client.pipeline()
    .set('foo', '1')
    .get('foo')
    .set('foo', '2')
    .incr('foo')
    .get('foo')
    .exec(function (err, results) {
      // Handle results or errors.
    });

对于 node-redis,方法类似,不同之处在于您调用 multi() 命令开始管道,并调用 execAsPipeline() 运行它

client.multi()
    .set('seat:3', '#3')
    .set('seat:4', '#4')
    .set('seat:5', '#5')
    .execAsPipeline()
    .then((results) => {
        // Handle array of results.
    },
    (err) => {
        // Handle errors.
    });

Scan 迭代

ioredis 支持 scanStream() 方法,用于从 SCAN 命令返回的键集合创建一个可读流

const client = new Redis();
// Create a readable stream (object mode)
const stream = client.scanStream();
stream.on('data', (resultKeys) => {
  // `resultKeys` is an array of strings representing key names.
  // Note that resultKeys may contain 0 keys, and that it will sometimes
  // contain duplicates due to SCAN's implementation in Redis.
  for (let i = 0; i < resultKeys.length; i++) {
    console.log(resultKeys[i]);
  }
});
stream.on('end', () => {
  console.log('all keys have been visited');
});

您也可以使用类似的 hscanStream()sscanStream()zscanStream() 分别迭代哈希、集合或有序集合中的项。

node-redis 使用 scanIterator() 方法(以及相应的 hscanIterator()sscanIterator()zscanIterator() 方法)处理 Scan 迭代。这些方法为游标扫描的每一页返回一个集合对象(这有助于使用 MGET 和其他多键命令提高效率)

for await (const keys of client.scanIterator()) {
  const values = await client.mGet(keys);
  // Process values...
}

订阅频道

ioredis 通过客户端对象上的 message 事件报告传入的发布/订阅消息(更多关于消息的信息,请参阅发布/订阅

client.on('message', (channel, message) => {
   console.log(Received message from ${channel}: ${message});
});

使用 node-redis,您使用 subscribe() 命令注册消息回调。此外,当您使用一个连接进行订阅时,该连接不能发出任何其他命令,因此您必须为订阅创建一个专用连接。使用 client.duplicate() 方法创建一个与原始连接具有相同设置的新连接。

const subscriber = client.duplicate();
await subscriber.connect();

await subscriber.subscribe('channel', (message) => {
   console.log(Received message: ${message});
});

SETNX 命令

ioredis 使用显式方法实现了 SETNX 命令

client.setnx('bike:1', 'bike');

node-redis 不提供 SETNX 方法,但通过 SET 命令的 NX 选项实现了相同的功能

await client.set('bike:1', 'bike', {'NX': true});

HMSET 命令

HMSET 命令自 Redis v4.0.0 起已被弃用,但 ioredis 仍支持它。使用 node-redis 时,您应该使用带有多个键值对的 HSET 命令。更多信息请参阅 HSET 命令页面。

CONFIG 命令

ioredis 支持 config() 方法来设置或获取服务器配置选项

client.config('SET', 'notify-keyspace-events', 'KEA');

node-redis 没有 config() 方法,但支持标准命令 configSet()configGet()configResetStat()configRewrite

await client.configSet('maxclients', '2000');
评价此页面
返回顶部 ↑