源地址:https://www.digitalocean.com/community/cheatsheets/how-to-manage-replicas-and-clients-in-redis
作者:Mark Drake

如何管理 Redis 的副本和客户端

Introduction

Redis 是一个开源的、运行在内存中的键值数据库。Redis 最受欢迎的功能之一是它对副本的支持:任何 Redis 服务器都可以将其数据复制到任何数量的副本中,从而实现高读取扩展性和强大的数据冗余。此外,Redis 被设计成允许多个客户端(默认情况下多达 10000 个)同时连接并进行数据交互,这个特性使得它成为多用户访问统一数据集下的好选择。本教程将介绍用于管理 Redis 客户端和副本的命令。

如何使用这个教程

这个教程是以小抄(Cheat Sheet)的形式写的,有对应的例子。我们鼓励你直接跳转到和你要完成的任务相关的章节进行阅读。

这个教程中的命令在 Ubuntu 18.04 中的 Redis 4.0.9 版本完成测试。如果你需要建设一个同样的环境,可以参考我们的 如何在 Ubuntu 18.04 上安装并加固 Redis 中的 Step 1 来安装 Redis。我们将通过 Redis 命令行界面redis-cli运行这些命令,来演示这些命令的行为。请注意,如果你使用不同的 Redis 工具--例如Redli —— 某些命令的实际输出可能有所不同。

此外,你还可以使用一个代管的 Redis 数据库实例来测试这些命令。但需要注意的是,根据你的数据库服务提供商的限制,这个教程中的某些命令可能运行效果和教程不一致。如果想要使用 DigitalOcean 提供的代管数据库,可以查看我们的代管数据库产品文档。使用代管 Redis 数据库实例时,你必须安装 Redli设置 TLS 隧道 来通过 TLS 链接到代管数据库。

注意:Redis 项目文档中使用 masterslave 来区分不同副本,虽然项目的贡献者正在采取措施来在不影响兼容性的情况下改变这个用法。Digital Ocean 一般倾向于使用替代词汇 primaryreplica

这个教程将默认使用 primaryreplica ,但某些特定情况下,无法完全避免 masterslave 的用法。

Managing Replicas

Redis 特点之一是它的内置副本。当使用副本时,Redis 将会创建主实例的精准拷贝。出现断连后,这些次要的副本将会在重新连接到主示例时,将会始终保持和主实例的精准拷贝。

如果你不确定你当前连接的 Redis 实例是主实例还是副本实例,你可以执行 role命令查看:

127.0.0.1:6379> role

如果你使用了 Redis Sentinel,这个命令可能会返回 masteslavesentinel 作为结果。

要动态地将 Redis 实例指定为另一个实例的副本,请运行 replicaof 命令。此命令以预期的主服务器的主机名或 IP 地址和端口作为参数:

127.0.0.1:6379> replicaof hostname_or_IP port

如果服务器已经是另一个主服务器的副本,它将停止复制旧服务器并立即开始与新服务器同步,并丢弃旧数据集。

要将副本变回主副本,请运行以下 replicaof 命令:

127.0.0.1:6379> replicaof no one

这将阻止实例复制主服务器,但不会丢弃它已经复制的数据集。此语法在原主节点失败的情况下很有用。在故障主节点的副本上运行 replicaof noone 后,当前节点可以用作新的主节点,并配置自己的副本作为故障保护。

注意: 在 5.0.0 版本之前,Redis 此命令的名字是 slaveof

管理客户端

客户端 是连接到服务器以访问服务的任何机器或软件。Redis 附带了几个命令,可帮助跟踪和管理客户端连接。

client list 命令返回一组易读的、关于当前客户端连接的信息。

127.0.0.1:6379> client list

输出

"
id=18165 addr=[2001:db8:0:0::12]:47460 fd=7 name=jerry age=72756 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=ping
id=18166 addr=[2001:db8:0:1::12]:47466 fd=8 name= age=72755 idle=5 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=info
id=19381 addr=[2001:db8:0:2::12]:54910 fd=9 name= age=9 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=32742 obl=0 oll=0 omem=0 events=r cmd=client
"

以下是每个字段的含义:

  • id: 唯一的 64 位客户端 ID
  • name: 客户端连接的名称,由之前执行的client setname命令定义
  • addr: 客户端连接的地址和端口
  • fd: 文件描述符,对应于客户端连接的 Socket
  • age: 以秒为单位,客户端连接的总时长。
  • flags: 一组一个或多个单字符标志,提供有关客户端的更详细的信息;可以查看 client list 命令文档 了解更多信息
  • db: 客户端连接的当前数据库 ID 号(可以从015
  • sub: 客户端订阅的频道数量
  • psub: 客户端模式匹配订阅的数量
  • mutli: 客户端在 事务 中排队的命令数。(-1表示客户端没有开始事务;0表示只开始了一个事务,且没有任何命令在队列中)。
  • qbuf: 客户端的查询缓冲区长度,0 表示它没有待处理的查询。
  • qbuf-free: 客户端查询缓冲区的可用空间量,0表示查询缓冲区已满
  • obl: 客户端的输出缓冲区长度
  • oll: 客户端输出列表的长度,当缓冲区满时将会进行排队
  • omem: 客户端输出缓冲区使用的内存
  • events: 客户端的文件描述符事件,这些可以是 r 表示“可读”,“w”表示“可写”,或两者兼而有之。
  • cmd: 客户端运行的最后一条命令

设置客户端名称对于调试任何使用 Redis 的应用程序中出现的连接泄漏很有用。默认情况下,每个新连接都没有设置名称,但可以使用client setname为当前客户端连接设置名称。客户端名称的长度没有限制,但 Redis 通常将字符串长度限制为 512 MB。需要注意的是,客户端名称不能包含空格:

127.0.0.1:6379> client setname elaine

使用 client getname 可以获取当前客户端的名称

127.0.0.1:6379> client getname

输出

"elaine"

使用 client id 命令可以获取到当前客户端的连接 ID

127.0.0.1:6379> client id

输出

(integer) "19492"

Redis 客户端 ID 从不重复,并且是单调递增的。这意味着如果一个客户端的 ID 大于另一个客户端,那么它是在另一个客户端建立以后建立的。

阻塞客户端并关闭客户端连接

副本系统通常被描述为_同步_或_异步_的。在同步复制中,每当客户端添加或更改数据时,它必须从一定数量的副本接收某种确认,以便将更改注册为已提交。这有助于防止节点发生数据冲突,但它是以延迟为代价的,因为客户端必须等待执行另一个操作,直到它收到一定数量的副本的回复。

另一方面,在异步复制中,一旦数据写入本地存储,客户端就会看到操作完成的确认。但是,这与副本实际写入数据的时间之间可能存在延迟。如果其中一个副本在写入更改之前发生故障,则该写入将永远丢失。因此,虽然异步复制允许客户端继续执行操作而不会因等待副本而产生延迟,但它可能会导致节点之间的数据冲突,并且可能需要数据库管理员额外的工作来解决这些冲突。

由于注重性能和低延迟,Redis 默认实现异步复制。但是,你可以使用 wait 命令模拟同步复制。 wait 将当前客户端连接阻塞指定的时间量(以毫秒为单位),直到所有先前的写入命令都成功传输并被指定数量的副本接受。此命令使用以下语法:

127.0.0.1:6379> wait number_of_replicas number_of_milliseconds

例如,如果你想阻止你的客户端连接,直到所有先前的写入在 30 毫秒超时内被至少 3 个副本注册,你的 wait 语法将如下所示:

127.0.0.1:6379> wait 3 30

wait 命令返回一个整数,表示确认写入命令的副本数量,即使不是每个副本都这样做:

输出

2

要解除之前通过 waitbrpopxread命令对先前客户端连接的阻塞,都可以使用以下语法运行client unblock命令:

127.0.0.1:6379> client unblock client_id

要暂时挂起当前连接到 Redis 服务器的每个客户端,可以使用 client pause 命令。这在你需要以可控的方式更改 Redis 设置的情况下很有用。例如,如果你将其中一个副本提升为主实例,你可能会提前暂停每个客户端,以便你可以提升副本并让客户端连接到它作为新的主实例,而不会丢失该过程中的任何写入操作。

client pause 可以指定要暂停客户端的时间量(以毫秒为单位)。以下示例将暂停所有客户端一秒钟:

127.0.0.1:6379> client pause 1000

client kill 允许你基于多个不同的过滤器关闭单个连接或一组特定连接。语法如下所示:

127.0.0.1:6379> client kill filter_1 value_1 ... filter_n value_n

在 Redis 2.8.12 及更高版本中,可以使用以下过滤器:

  • addr: 允许你关闭来自指定 IP 地址和端口的客户端连接
  • client-id: 允许你根据其唯一 ID 字段关闭客户端连接
  • type: 关闭特定类型的每个客户端,可以是 normalmasterslavepubsub
  • skipme: 此过滤器的值选项是 yesno
    • 如果指定了 no,调用 client kill 命令的客户端将不会被跳过,如果其他过滤器适用于它,它也将被杀死。。
    • 如果指定了yes,将跳过运行该命令的客户端,kill 命令对客户端没有任何影响。默认 情况下,skipme 的值是 yes

总结

本指南详细介绍了一些用于管理 Redis 客户端和副本的命令。