警告: 本文档是一份草案,其中包含的指南可能会随着 Sentinel 项目的演进在未来发生变化。
*支持 Redis Sentinel 的 Redis 客户端指南
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 客户端有一些硬编码配置,指定网络中 Redis 主节点实例的地址为 IP 地址和端口号。然而如果主节点地址发生变化,需要手动干预每个客户端。
支持 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 主节点实例建立了连接,每次需要重新连接时,客户端应使用 Sentinel 重新解析地址,从第 1 步开始。例如,在以下情况下应再次联系 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 都用空回复回复,应通过错误告知用户 Sentinels 不知道这个主节点名称。
*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 发送消息。