Node-Redis
node-redis 是一个现代、高性能的 Redis 的 Node.js 客户端。
如何开始使用 Redis?
安装
通过 docker 启动一个 redis:
docker run -p 6379:6379 -d redis:8.0-rc1
要安装 node-redis,只需:
npm install redis
"redis" 是包含所有其他包的"一体化"包。如果你只需要部分命令, 可以单独安装相应的包。参见以下列表。
包
| 名称 | 描述 |
|---|---|
redis | 包含所有 "redis-stack" 模块的客户端 |
@redis/client | 基础客户端(即 RedisClient、RedisCluster 等) |
@redis/bloom | Redis Bloom 命令 |
@redis/json | Redis JSON 命令 |
@redis/search | RediSearch 命令 |
@redis/time-series | Redis Time-Series 命令 |
@redis/entraid | 使用 Microsoft Entra ID 为 Redis 客户端提供基于令牌的安全身份验证 |
正在寻找用于处理对象映射的高级库? 参见 redis-om-node!
用法
基本示例
import { createClient } from "redis";
const client = await createClient()
.on("error", (err) => console.log("Redis Client Error", err))
.connect();
await client.set("key", "value");
const value = await client.get("key");
console.log(value); // 'value'
client.destroy();
相同的示例在 CommonJS 中(例如 node example.js 在 package.json 中没有 "type": "module"):
const { createClient } = require("redis");
async function main() {
const client = await createClient()
.on("error", (err) => console.log("Redis Client Error", err))
.connect();
await client.set("key", "value");
const value = await client.get("key");
console.log(value); // 'value'
client.destroy();
}
main().catch(console.error);
上述代码连接到 localhost 的 6379 端口。要连接到不同的主机或端口,请使用格式为 redis[s]://[[username][:password]@][host][:port][/db-number] 的连接字符串:
createClient({
url: "redis://alice:foobared@awesome.redis.server:6380",
});
您还可以使用离散参数、UNIX 套接字,甚至 TLS 进行连接。详细信息请参阅 客户端配置指南。
要检查客户端是否已连接并准备好发送命令,请使用 client.isReady,它将返回一个布尔值。
client.isOpen 也可用。当客户端的底层套接字打开时,它返回 true,当套接字未打开时
(例如,当客户端仍在连接或在网络错误后重新连接时),它返回 false。
Redis 命令
内置支持所有 开箱即用的 Redis 命令。它们通过原始的 Redis 命令名称(HSET、HGETALL 等)
以及更友好的驼峰式命名版本(hSet、hGetAll 等)暴露:
// raw Redis commands
await client.HSET("key", "field", "value");
await client.HGETALL("key");
// friendly JavaScript commands
await client.hSet("key", "field", "value");
await client.hGetAll("key");
命令的修饰符使用 JavaScript 对象指定:
await client.set("key", "value", {
EX: 10,
NX: true,
});
回复将被转换为有用的数据结构:
await client.hGetAll("key"); // { field1: 'value1', field2: 'value2' }
await client.hVals("key"); // ['value1', 'value2']
Buffers 同样受支持:
const client = createClient().withTypeMapping({
[RESP_TYPES.BLOB_STRING]: Buffer
});
await client.hSet("key", "field", Buffer.from("value")); // 'OK'
await client.hGet("key", "field"); // { field: <Buffer 76 61 6c 75 65> }
对于返回序列化二进制负载的命令,例如 DUMP,在使用诸如 RESTORE 等命令处理结果之前,请将 blob 字符串映射为 Buffer:
const binaryClient = createClient().withTypeMapping({
[RESP_TYPES.BLOB_STRING]: Buffer
});
const dump = await binaryClient.dump("source");
await binaryClient.restore("destination", 0, dump);
不支持的 Redis 命令
如果你想执行 Node Redis 尚不识别的命令和/或使用参数(目前!),请使用 .sendCommand():
await client.sendCommand(["SET", "key", "value", "NX"]); // 'OK'
await client.sendCommand(["HGETALL", "key"]); // ['key1', 'field1', 'key2', 'field2']
注意:使用集群时,API 有所不同。
事务 (Multi/Exec)
通过调用 .multi() 来开始一个 事务,然后链式调用你的命令。当你
完成后,调用 .exec(),你将得到一个包含结果的数组:
await client.set("another-key", "another-value");
const [setKeyReply, otherKeyValue] = await client
.multi()
.set("key", "value")
.get("another-key")
.exec(); // ['OK', 'another-value']
你还可以通过调用
.watch() 来 监视 键。如果任何被监视的键发生变化,你的事务将会中止。
阻塞命令
在 v4 中,RedisClient 能够在“主”
连接之上使用“隔离池”来创建连接池。然而,没有方法可以在没有“主”连接的情况下使用该池:
const client = await createClient()
.on("error", (err) => console.error(err))
.connect();
await client.ping(client.commandOptions({ isolated: true }));
在 v5 中,我们将此池逻辑提取到了其自身的类中——RedisClientPool:
const pool = await createClientPool()
.on("error", (err) => console.error(err))
.connect();
await pool.ping();
Pub/Sub
参见 Pub/Sub 概述。
Scan Iterator
SCAN 的结果可以使用 async iterators 进行遍历:
for await (const keys of client.scanIterator()) {
console.log(keys, await client.mGet(keys));
}
这在 HSCAN、SSCAN 和 ZSCAN 中同样适用:
for await (const { field, value } of client.hScanIterator("hash")) {
}
for await (const member of client.sScanIterator("set")) {
}
for await (const { score, value } of client.zScanIterator("sorted-set")) {
}
您可以通过提供配置对象来覆盖默认选项:
client.scanIterator({
TYPE: "string", // `SCAN` only
MATCH: "pattern*",
COUNT: 100,
});
比较并设置/删除 (CAS/CAD)
注意: CAS/CAD 操作在 Redis 8.4 中引入
// Conditionally update only if the current value matches
await client.set("key", "new-value", { condition: "IFEQ", matchValue: "old-value" });
// Conditionally delete only if the current value matches
await client.delEx("key", { condition: "IFEQ", matchValue: "expected-value" });
本地摘要
注意:此功能需要可选的
@node-rs/xxhash对等依赖。
digest 辅助函数在本地计算 XXH3 64 位哈希,与 Redis 通过 DIGEST 命令计算的结果一致。这在处理大值的 CAS/CAD 操作中非常有用,因为比较完整值会效率低下。
npm install @node-rs/xxhash
import { digest } from "redis";
const hash = await digest("my-value");
await client.set("key", "new-value", { condition: "IFDEQ", matchValue: hash });
断开连接
QUIT 命令在 Redis 7.2 中已被弃用,在 Node-Redis 中也应视为已弃用。客户端无需再向服务器发送 QUIT 命令,只需直接关闭网络连接即可。
client.QUIT/quit() 已被 client.close() 取代。此外,为避免混淆,client.disconnect() 已重命名为
client.destroy()。
client.destroy();
客户端缓存
Node Redis v5 增加了对 客户端缓存 的支持,该功能允许客户端在本地缓存查询结果。当缓存的结果不再有效时,Redis 服务器会通知客户端。
// Enable client side caching with RESP3
const client = createClient({
RESP: 3,
clientSideCache: {
ttl: 0, // Time-to-live (0 = no expiration)
maxEntries: 0, // Maximum entries (0 = unlimited)
evictPolicy: "LRU" // Eviction policy: "LRU" or "FIFO"
}
});
请参阅 V5 文档 以获取更多详细信息和高级用法。
自动管道化
Node Redis 会自动将同一 "tick" 期间发出的请求进行管道化处理。
client.set("Tm9kZSBSZWRpcw==", "users:1");
client.sAdd("users:1:tokens", "Tm9kZSBSZWRpcw==");
当然,如果你不对你的 Promises 做任何处理,你肯定会
遇到 未处理的 Promise 异常。要利用
自动流水线并处理你的 Promises,请使用 Promise.all()。
await Promise.all([
client.set("Tm9kZSBSZWRpcw==", "users:1"),
client.sAdd("users:1:tokens", "Tm9kZSBSZWRpcw=="),
]);
Sentinel
查看 sentinel 部分 以了解如何使用哨兵使用该库。
Programmability
Clustering
使用 Node Redis 连接 Redis Cluster 时,请查阅 Clustering 指南。
OpenTelemetry
OpenTelemetry Metrics Instrumentation
import { createClient, OpenTelemetry } from "redis";
OpenTelemetry.init({
metrics: {
enabled: true
}
});
const client = createClient()
await client.connect();
// ... use the client as usual
重要: 初始化 OpenTelemetry 仅启用 node-redis 指标插桩,并且需要 @opentelemetry/api 以及在您的应用程序中配置的 OpenTelemetry SDK。
重要: 在创建 Redis 客户端之前初始化 OpenTelemetry。
有关 SDK/提供者/导出器的设置、验证和高级配置,请参阅:
Diagnostics Channel
Node Redis 通过 Node.js diagnostics_channel 发布遥测数据,使 APM 工具和自定义插桩能够观察命令、连接和内部事件。有关完整的通道参考和使用示例,请参阅 Diagnostics Channel 指南。
Events
Node Redis 客户端类是一个 Nodejs EventEmitter,每次网络状态发生变化时都会发出一个事件:
| 名称 | 触发时机 | 监听器参数 |
|---|---|---|
connect | 发起与服务器的连接 | 无参数 |
ready | 客户端已准备就绪 | 无参数 |
end | 连接已关闭(通过 .close() 或 .destroy()) | 无参数 |
error | 发生错误——通常是网络问题,例如 "Socket closed unexpectedly" | (error: Error) |
reconnecting | 客户端正在尝试重新连接到服务器 | 无参数 |
sharded-channel-moved | 参见 此处 | 参见 此处 |
invalidate | 客户端跟踪(Client Tracking)已启用 emitInvalidate 且某个键被失效 | (key: RedisItem | null) |
:warning: 你必须监听
error事件。如果客户端没有注册至少一个error监听器,并且 发生了error,该错误将被抛出,Node.js 进程将退出。有关更多详细信息,请参阅 >EventEmitter文档。
客户端不会发出上述列表之外的任何其他事件。
支持的 Redis 版本
Node Redis 支持以下版本的 Redis:
请参阅 支持的 Redis 版本。
迁移
贡献
如果你想做出贡献,请查看贡献指南。
感谢所有已经为 Node Redis 做出贡献的人!
许可证
本仓库采用 "MIT" 许可证。参见 LICENSE.