从 ioredis 迁移
了解 ioredis
与 node-redis
之间的区别。
Redis 之前推荐使用 ioredis
客户端库进行 Node.js 开发,但该库现已弃用,推荐使用 node-redis
。本指南概述了这两个库之间的主要异同。如果您是 ioredis
用户,并且想启动新的 Node.js 项目或将现有的 ioredis
项目迁移到 node-redis
,您可能会发现此信息很有用。
ioredis
与 node-redis
对比
下表总结了 ioredis
和 node-redis
如何实现 Redis 的一些关键特性。有关每个特性的更多信息,请参阅以下部分。
连接
特性 | ioredis |
node-redis |
---|---|---|
初始化连接 | 在创建客户端实例时发生 | 需要您在客户端实例上调用一个方法 |
连接丢失后重新连接 | 默认为自动 | 默认为手动 |
连接事件 | 发出 connect 、ready 、error 和 close 事件 |
发出 connect 、ready 、error 、end 和 reconnecting 事件 |
命令处理
特性 | ioredis |
node-redis |
---|---|---|
命令大小写 | 仅小写(例如 hset ) |
大写或驼峰式大小写(例如 HSET 或 hSet ) |
命令参数处理 | 参数对象展平并直接传递各项 | 解析参数对象以生成正确的参数列表 |
异步命令结果处理 | 回调和 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() 等方法 |
详细信息
以下部分更详细地解释了 ioredis
和 node-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
发出的 connect
、ready
、error
和 close
事件等同于 node-redis
中的 connect
、ready
、error
和 end
事件,但 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});
异步命令结果处理
ioredis
和 node-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();
管道
如果 ioredis
和 node-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');