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 开始使用 Sentinels 再次解析地址。例如,在以下情况下应再次联系 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 文档展示了客户端如何使用 Pub/Sub 连接到 Sentinel 实例,以便订阅 Redis 实例配置的更改。
可以使用此机制来加速客户端的重新配置,即客户端可以监听 Pub/Sub,以便在配置更改发生时得知,从而运行本文档中解释的三步协议来解析新的 Redis 主节点(或副本节点)地址。
但是,通过 Pub/Sub 收到的更新消息不应取代上述过程,因为无法保证客户端能够收到所有更新消息。
附加信息
如需附加信息或讨论本指南的特定方面,请在 Redis Google Group 中留言。