Sentinel 客户端规范
如何为 Redis Sentinel 构建客户端
Redis Sentinel 是 Redis 实例的监控解决方案,它处理 Redis 主服务器的自动故障转移和服务发现(谁是给定实例组的当前主服务器?)。由于 Sentinel 既负责在故障转移期间重新配置实例,又负责向连接到 Redis 主服务器或副本的客户端提供配置,因此客户端需要显式支持 Redis Sentinel。
本文档面向想要在他们的客户端实现中支持 Sentinel 的 Redis 客户端开发人员,其目标如下
- 通过 Sentinel 自动配置客户端。
- 提高 Redis Sentinel 自动故障转移的安全性。
有关 Redis Sentinel 工作原理的详细信息,请查看 Redis 文档,因为本文档仅包含 Redis 客户端开发人员所需的信息,并且预计读者熟悉 Redis Sentinel 的工作方式。
通过 Sentinel 进行 Redis 服务发现
Redis Sentinel 使用诸如“stats”或“cache”之类的名称标识每个主服务器。每个名称实际上标识一个实例组,该组由一个主服务器和可变数量的副本组成。
网络中用于特定用途的 Redis 主服务器的地址可能会在发生以下事件后发生更改:例如自动故障转移、手动触发的故障转移(例如为了升级 Redis 实例)以及其他原因。
通常,Redis 客户端会有一些硬编码的配置,以 IP 地址和端口号的形式指定网络中 Redis 主实例的地址。但是,如果主地址发生变化,则需要对每个客户端进行手动干预。
支持 Sentinel 的 Redis 客户端可以使用 Redis Sentinel 自动发现 Redis 主服务器的地址。因此,支持 Sentinel 的客户端可以接受以下输入,而不是硬编码的 IP 地址和端口:
- 指向已知 Sentinel 实例的 ip:port 对列表。
- 服务名称,例如“cache”或“timelines”。
这是客户端从 Sentinel 列表和服务名称开始获取主地址应遵循的步骤。
步骤 1:连接到第一个 Sentinel
客户端应该遍历 Sentinel 地址列表。对于每个地址,它应该尝试连接到 Sentinel,并使用一个短超时时间(大约几百毫秒)。如果出现错误或超时,则应尝试下一个 Sentinel 地址。
如果所有 Sentinel 地址都尝试过但没有成功,则应向客户端返回错误。
第一个回复客户端请求的 Sentinel 应放在列表的开头,这样在下次重新连接时,我们将首先尝试在先前连接尝试中可达的 Sentinel,从而最大限度地减少延迟。
步骤 2:请求主地址
一旦与 Sentinel 建立连接,客户端应尝试在 Sentinel 上执行以下命令:
SENTINEL get-master-addr-by-name master-name
其中 *master-name* 应替换为用户指定的实际服务名称。
此调用的结果可能是以下两种回复之一:
- 一个 ip:port 对。
- 一个空回复。这意味着 Sentinel 不知道此主服务器。
如果收到 ip:port 对,则应使用此地址连接到 Redis 主服务器。否则,如果收到空回复,客户端应尝试列表中的下一个 Sentinel。
步骤 3:在目标实例中调用 ROLE 命令
一旦客户端发现了主实例的地址,它应该尝试与主服务器建立连接,并调用 ROLE
命令来验证实例的角色实际上是主服务器。
如果 ROLE
命令不可用(它是在 Redis 2.8.12 中引入的),客户端可以求助于 INFO replication
命令解析输出的 role:
字段。
如果实例不是预期中的主服务器,客户端应等待一小段时间(几百毫秒),然后从步骤 1 开始重新尝试。
处理重新连接
一旦服务名称解析为主地址,并且与 Redis 主实例建立了连接,每当需要重新连接时,客户端都应从步骤 1 开始重新解析地址,使用 Sentinel 重新解析地址。例如,在以下情况下,Sentinel 应再次联系:
- 如果客户端在超时或套接字错误后重新连接。
- 如果客户端重新连接是因为它被用户显式关闭或重新连接。
在上述情况和其他任何客户端丢失与 Redis 服务器连接的情况中,客户端应重新解析主地址。
Sentinel 故障转移断开连接
从 Redis 2.8.12 开始,当 Redis Sentinel 更改实例的配置时,例如将副本提升为主服务器,在故障转移后将主服务器降级为复制到新的主服务器,或者只是更改陈旧副本实例的主地址,它会向实例发送一个 CLIENT KILL type normal
命令,以确保所有客户端都从重新配置的实例断开连接。这将迫使客户端重新解析主地址。
如果客户端联系了尚未更新信息的 Sentinel,则通过 ROLE
命令验证 Redis 实例角色将失败,使客户端能够检测到已联系的 Sentinel 提供了陈旧信息,并将重新尝试。
注意:一个陈旧的主服务器可能在客户端联系陈旧的 Sentinel 实例的同时恢复在线状态,因此客户端可能与陈旧的主服务器连接,但 ROLE 输出仍然匹配。但是,当主服务器再次恢复在线状态时,Sentinel 会尝试将其降级为副本,从而触发新的断开连接。相同的推理适用于连接到将被重新配置为复制到不同主服务器的陈旧副本。
连接到副本
有时,客户端会希望连接到副本,例如为了扩展读取请求。此协议通过稍微修改步骤 2 来支持连接到副本。而不是调用以下命令:
SENTINEL get-master-addr-by-name master-name
客户端应改为调用:
SENTINEL replicas master-name
以便检索副本实例列表。
类似地,客户端应该使用 ROLE
命令验证实例实际上是一个副本,以避免使用主服务器扩展读取查询。
连接池
对于实现连接池的客户端,在单个连接重新连接时,应再次联系 Sentinel,如果主地址发生更改,则应关闭所有现有连接并连接到新地址。
错误报告
如果出现错误,客户端应正确将信息返回给用户。具体来说:
- 如果无法联系到任何 Sentinel(因此客户端永远无法获取对
SENTINEL get-master-addr-by-name
的回复),则应返回一个明确指出 Redis Sentinel 不可达的错误。 - 如果池中的所有 Sentinel 都以空回复回复,则应向用户发送一个错误消息,告知 Sentinel 不知道此主服务器名称。
Sentinel 列表自动刷新
可选地,一旦成功接收到对 get-master-addr-by-name
的回复,客户端可以使用以下步骤更新其内部 Sentinel 节点列表:
- 使用命令
SENTINEL sentinels <master-name>
获取此主服务器的其他 Sentinel 列表。 - 将列表中不存在的每个 ip:port 对添加到列表的末尾。
客户端不需要能够通过更新其自身的配置来使列表持久化。能够升级 Sentinel 列表的内存表示本身就已经很有用,可以提高可靠性。
订阅 Sentinel 事件以提高响应速度
Sentinel 文档 说明了客户端如何使用发布/订阅连接到 Sentinel 实例,以订阅 Redis 实例配置的变化。
此机制可用于加快客户端的重新配置,也就是说,客户端可以监听发布/订阅,以便了解何时发生了配置更改,以便运行本文档中解释的三个步骤协议以解析新的 Redis 主服务器(或副本)地址。
但是,通过发布/订阅接收的更新消息不应该替代上述过程,因为无法保证客户端能够接收所有更新消息。
其他信息
有关更多信息或讨论这些指南的特定方面,请向 Redis Google Group 发送消息。