在 Node.js 中操作 Redis
Node.js 中可以操作 Redis 的软件包推荐列表:https://redis.io/clients#nodejs。
推荐下面两个:
这里主要以 ioredis 为例。
ioredis 特点:
- 功能齐全。它支持集群,前哨,流,流水线,当然还支持Lua脚本和发布/订阅(具有二进制消息的支持)。
- 高性能
- 令人愉快的 API。它的异步 API 支持回调函数与 Promise
- 命令参数和返回值的转换
- 透明键前缀
- Lua脚本的抽象,允许您定义自定义命令。
- 支持二进制数据
- 支持 TLS
- 支持脱机队列和就绪检查
- 支持ES6类型,例如 Map 和 Set
- 支持GEO命令(Redis 3.2不稳定)
- 复杂的错误处理策略
- 支持NAT映射
- 支持自动流水线
基本使用
npm install ioredis
const Redis = require("ioredis");
const redis = new Redis(); // uses defaults unless given configuration object
// ioredis supports all Redis commands:
redis.set("foo", "bar"); // returns promise which resolves to string, "OK"
// the format is: redis[SOME_REDIS_COMMAND_IN_LOWERCASE](ARGUMENTS_ARE_JOINED_INTO_COMMAND_STRING)
// the js: ` redis.set("mykey", "Hello") ` is equivalent to the cli: ` redis> SET mykey "Hello" `
// ioredis supports the node.js callback style
redis.get("foo", function (err, result) {
if (err) {
console.error(err);
} else {
console.log(result); // Promise resolves to "bar"
}
});
// Or ioredis returns a promise if the last argument isn't a function
redis.get("foo").then(function (result) {
console.log(result); // Prints "bar"
});
// Most responses are strings, or arrays of strings
redis.zadd("sortedSet", 1, "one", 2, "dos", 4, "quatro", 3, "three");
redis.zrange("sortedSet", 0, 2, "WITHSCORES").then((res) => console.log(res)); // Promise resolves to ["one", "1", "dos", "2", "three", "3"] as if the command was ` redis> ZRANGE sortedSet 0 2 WITHSCORES `
// All arguments are passed directly to the redis server:
redis.set("key", 100, "EX", 10);
有关更多实例,可以参考这里:https://github.com/luin/ioredis/tree/master/examples。
Pipelining
如果要发送一批命令(例如> 5),则可以使用流水线将命令在内存中排队,然后将它们一次全部发送到 Redis。这样,性能提高了50%〜300%(请参阅基准测试部分)。
redis.pipeline() 创建一个 Pipeline 实例。您可以像 Redis 实例一样在其上调用任何 Redis 命令。这些命令在内存中排队,并通过调用 exec 方法刷新到 Redis:
const pipeline = redis.pipeline();
pipeline.set("foo", "bar");
pipeline.del("cc");
pipeline.exec((err, results) => {
// `err` is always null, and `results` is an array of responses
// corresponding to the sequence of queued commands.
// Each response follows the format `[err, result]`.
});
// You can even chain the commands:
redis
.pipeline()
.set("foo", "bar")
.del("cc")
.exec((err, results) => {});
// `exec` also returns a Promise:
const promise = redis.pipeline().set("foo", "bar").get("foo").exec();
promise.then((result) => {
// result === [[null, 'OK'], [null, 'bar']]
});
每个链接的命令还可以具有一个回调,该回调将在命令得到答复时被调用:
redis
.pipeline()
.set("foo", "bar")
.get("foo", (err, result) => {
// result === 'bar'
})
.exec((err, result) => {
// result[1][1] === 'bar'
});
除了将命令分别添加到管道队列之外,您还可以将命令和参数数组传递给构造函数:
redis
.pipeline([
["set", "foo", "bar"],
["get", "foo"],
])
.exec(() => {
/* ... */
});
const length = redis.pipeline().set("foo", "bar").get("foo").length;
// length === 2
事务
大多数时候,事务命令 multi&exec 与管道一起使用。因此,在调用 multi 时,默认情况下会自动创建 Pipeline 实例,因此您可以像使用管道一样使用 multi:
redis
.multi()
.set("foo", "bar")
.get("foo")
.exec((err, results) => {
// results === [[null, 'OK'], [null, 'bar']]
});
如果事务的命令链中存在语法错误(例如,错误的参数数量,错误的命令名称等),则不会执行任何命令,并返回错误:
redis
.multi()
.set("foo")
.set("foo", "new value")
.exec((err, results) => {
// err:
// { [ReplyError: EXECABORT Transaction discarded because of previous errors.]
// name: 'ReplyError',
// message: 'EXECABORT Transaction discarded because of previous errors.',
// command: { name: 'exec', args: [] },
// previousErrors:
// [ { [ReplyError: ERR wrong number of arguments for 'set' command]
// name: 'ReplyError',
// message: 'ERR wrong number of arguments for 'set' command',
// command: [Object] } ] }
});
就接口而言,multi 与管道的区别在于,当为每个链接的命令指定回调时,排队状态将传递给回调,而不是命令的结果:
redis
.multi()
.set("foo", "bar", (err, result) => {
// result === 'QUEUED'
})
.exec(/* ... */);
如果要使用不带管道的事务,请将 { pipeline: false } 传递给 multi,每个命令将立即发送到 Redis,而无需等待 exec 调用:
redis.multi({ pipeline: false });
redis.set("foo", "bar");
redis.get("foo");
redis.exec((err, result) => {
// result === [[null, 'OK'], [null, 'bar']]
});
redis
.multi([
["set", "foo", "bar"],
["get", "foo"],
])
.exec(() => {
/* ... */
});
管道支持内联事务,这意味着您可以将管道中的命令子集分组为一个事务:
redis
.pipeline()
.get("foo")
.multi()
.set("foo", "bar")
.get("foo")
.exec()
.get("foo")
.exec();
错误处理
Redis服务器返回的所有错误都是 ReplyError 的实例,可以通过 Redis 进行访问:
const Redis = require("ioredis");
const redis = new Redis();
// This command causes a reply error since the SET command requires two arguments.
redis.set("foo", (err) => {
err instanceof Redis.ReplyError;
});
默认情况下,错误堆栈没有任何意义,因为整个堆栈都发生在 ioredis 模块本身而不是代码中。因此,要找出错误在代码中的位置并不容易。 ioredis 提供了一个选项 showFriendlyErrorStack 来解决该问题。启用 showFriendlyErrorStack 时,ioredis 将为您优化错误堆栈:
const Redis = require("ioredis");
const redis = new Redis({ showFriendlyErrorStack: true });
redis.set("foo");
Redis 集群
对于一个小型项目来说,使用一台 Redis 服务器已经非常足够了,然后现实中的项目通常需要若干台 Redis 服务器的支持:
- 从结构上,单个 Redis 服务器会发生单点故障,同时一台服务器需要承受所有的请求负载。这就需要为数据生成多个副本并分配在不同的服务器上;
- 从容量上,单个 Redis 服务器的内存非常容易成为存储瓶颈,所有需要进行数据分片
同时拥有多个 Redis 服务器后就会面临如何管理集群的问题,包括如何增加节点、故障恢复等。
为此,我们将依次介绍 Redis 中的复制、哨兵(sentinel)和集群的使用和原理。
复制
通过持久化功能,Redis 保证了即使在服务器重启的情况下也不会损失(或少量损失)数据。但是由于数据是存储在一台服务器上的,如果这台服务器出现硬盘故障等问题,也会导致数据丢失。为了避免单点故障,通常的做法是将数据库复制多个副本以部署在不同的服务器上,这样即使有一台服务器出现故障,其它服务器依然可以继续提供服务。为此,Redis 提供了复制功能,可以实现当一台数据库中的数据更新后,自动将更新的数据同步到其它数据库上。
配置
slaveof 主数据库地址 主数据库端口
(1)开启两个 Redis 服务进程
为了能够更直观的展示复制的流程,下面将实现一个最简化的复制系统。我们要在一台服务器上启动两个 Redis 实例,监听不同端口,其中一个作为主数据库,另一个作为从数据库。首先我们不加任何参数来启动一个 Redis 实例作为主数据库:
redis-server
该实例默认监听 6379 端口。然后加上 slaveof 参数启动另一个 Redis 实例作为从数据库,并让其监听 6380 端口;
redis-server --port 6380 --slaveof 127.0.0.1 6379
(2)查看复制信息
INFO replication
(3)测试数据同步效果
在实例 A 中写入数据,会被自动同步到实例 B 中。
(4)从数据库中的数据是只读的
默认情况下,从数据库是只读的,如果直接修改从数据库的数据会出现错误:
INFO replication
可以通过设置从数据库的配置文件中的 slave–read–only 为 no 以使从数据库可写,但是因为对从数据库的任何更改都不会同步给任何其它数据库,并且一旦主数据库中更新了对应的数据就会覆盖从数据库中的改动,所有通常的场景下不应该设置从数据库可写,以免导致被忽略的潜在应用逻辑错误。
配置多台从数据库的方法也一样,在所有的从数据库的配置文件中都加上 slaveof 参数指向同一个主数据库即可。
除了通过配置文件或命令行参数设置 slaveof 参数,还可以在运行时使用 SLAVEOF 命令修改。
Redis 设置远程连接
注意:为了保护数据安全,开放远程连接需谨慎操作。
Redis 默认是不允许远程连接的,通过下面的配置可以开启远程连接。
将 redis.conf 配置文件的 bind 和 protected-mode 修改如下:
# 绑定的端口号
bind 0.0.0.0
# 关闭保护模式
protected-mode no
# RDB 持久化
save 900 1 # 每 900 秒至少有 1 个 key 变化了,则写入快照
save 300 10 # 每 300 秒至少有 10 个 key 变化了,则写入快照
save 60 10000 # 每 60 秒至少有 10000 个 key 变化了,则写入快照
dbfilename dump.rdb # 快照保存的文件名称
dir ./ # 快照文件保存路径
# 开启 AOF 方式的持久化
appendonly yes
# 同步的文件名称
appendfilename "appendonly.aof"
除此之外还需要检查服务器防火墙是否开放了 Redis 服务占用的端口号。
修改之后重启 Redis 服务即可生效。
执行
redis-server 配置文件路径
在docker上使用到的相关命令行
# Liunx命令
cd /etc
rm -rf 6379.conf
cp /app/redis-6.0.9/redis.conf ./6379.conf
cd redis
mv ../6379.conf ./
vim 6379.conf
#bash: vi: command not found
apt-get install vim
apt-get update
apt-get install vim
vim 6379.conf
#/6397 回车查找 按n下一个 把port改为1234
#/daemonize 回车查找 把no 改为 yes (在后台运行)
#按esc :wq回车 保存退出
#redis-server 6379.conf
#redis-cli
#select 1 切换到1号数据库
项目地址
原文地址:https://blog.csdn.net/qq_42308316/article/details/128112821
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_43588.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!