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客户端会有某种硬编码的配置,用于指定网络中Redis主实例的地址,包括IP地址和端口号。然而,如果主地址发生变化,则需要在每个客户端中进行手动干预。
支持Sentinel的Redis客户端可以使用Redis Sentinel从主服务器名称自动发现Redis主服务器的地址。因此,支持Sentinel的客户端应该能够选择性地接受以下输入,而不是硬编码的IP地址和端口:
- 指向已知Sentinel实例的ip:port对列表。
- 服务的名称,如“cache”或“timelines”。
这是客户端应遵循的程序,以便从Sentinels列表和服务名称开始获取主地址。
步骤1:连接到第一个Sentinel
客户端应遍历哨兵地址列表。对于每个地址,它应尝试使用较短的超时时间(大约几百毫秒)连接到哨兵。如果出现错误或超时,应尝试下一个哨兵地址。
如果所有Sentinel地址都尝试过但没有成功,应该向客户端返回一个错误。
第一个响应客户端请求的Sentinel应该放在列表的开头,这样在下一次重新连接时,我们会首先尝试在上一次连接尝试中可达的Sentinel,从而最小化延迟。
步骤2:请求主地址
一旦与Sentinel建立连接,客户端应重试在Sentinel上执行以下命令:
SENTINEL get-master-addr-by-name master-name
其中master-name应替换为用户指定的实际服务名称。
此调用的结果可能是以下两种回复之一:
- 一个ip:端口对。
- 空回复。这意味着Sentinel不知道这个主节点。
如果接收到一个ip:port对,应使用此地址连接到Redis主服务器。否则,如果接收到空回复,客户端应尝试列表中的下一个Sentinel。
步骤3:在目标实例中调用ROLE命令
一旦客户端发现主实例的地址,它应该尝试与主实例建立连接,并调用ROLE
命令以验证实例的角色确实是主实例。
如果ROLE
命令不可用(该命令在Redis 2.8.12中引入),客户端可以尝试使用INFO replication
命令解析输出的role:
字段。
如果实例不是预期的主节点,客户端应等待一小段时间(几百毫秒),然后应从步骤1重新尝试。
处理重新连接
一旦服务名称解析为主地址并与Redis主实例建立连接,每次需要重新连接时,客户端应使用Sentinels重新解析地址,从步骤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不可达的错误。 - 如果池中的所有哨兵都回复了空回复,用户应该被告知一个错误,即哨兵不知道这个主名称。
哨兵列表自动刷新
可选地,一旦收到对get-master-addr-by-name
的成功回复,客户端可以按照以下步骤更新其内部的Sentinel节点列表:
- 使用命令
SENTINEL sentinels
获取此主节点的其他哨兵列表。 - 将列表中尚未存在的每个ip:port对添加到列表末尾。
客户端不需要能够使列表持久化以更新其自己的配置。能够升级Sentinels列表的内存表示已经可以提高可靠性。
订阅Sentinel事件以提高响应能力
Sentinel 文档展示了客户端如何使用 Pub/Sub 连接到 Sentinel 实例,以订阅 Redis 实例配置的更改。
这种机制可以用来加速客户端的重新配置,也就是说,客户端可以监听Pub/Sub以了解何时发生了配置更改,从而运行本文档中解释的三步协议,以解析新的Redis主节点(或副本)地址。
然而,通过Pub/Sub接收到的更新消息不应替代上述程序,因为无法保证客户端能够接收所有更新消息。
附加信息
如需更多信息或讨论本指南的具体方面,请向Redis Google Group发送消息。