Redis 3.0官方文档翻译计划(15)
——高可用客户端指引
本文档是一篇草案,其包含的指引将来可能会随着Sentinel项目的进展而改变。
支持Redis Sentinel的Redis客户端指引
Redis Sentinel是Redis实例的监控解决方案,处理Redis主服务器的自动故障转移和服务
发现(谁是一组实例中的当前主服务器)。由于Sentinel具有在故障转移期间重新配置实例,以及提供配置给连接Redis主服务器或者从服务器的客户端的双重
责任,客户端需要有对Redis Sentinel的显式支持。
这篇文档针对Redis客户端开发人员,
他们想在其客户端实现中支持Sentinel,以达到如下目标:
- 通过Sentinel实现客户端的自动配置。
- 改进Sentinel自动故障转移的安全性。
要想获得Redis Sentinel如何工作的细节,请查看相关文档(请查看本系列相关文章,译者注),本文只包含Redis客户端开发人员需要的信息,期待读者已经比较熟悉Redis Sentinel的工作方式。
通过Sentinel实现Redis服务发现(Redis service discovery)
Redis Sentinel通过像”stats”或”cache”这样的名字来识别每个主服务器。每个名字实际上标识了一组实例,由一个主服务器和若干个从服务器组成。
网络中用于特定目的的Redis主服务器的地址,在一些像自动故障转移,手工触发故障转移(例如,为了提升一个Redis实例),或者其他原因引起的这样的事件后可能会改变。
通常,Redis客户端中有一些硬
编码的配置来指定IP地址和端口作为网络中Redis主服务器的地址。但是,如果主服务器的地址改变了,就需要手工介入到每个客户端了。
支持Sentinel的Redis客户端可以从使用Sentinel的主服务器的名称自动发现Redis的地址。所以支持Sentinel的客户端应该可以从输入中获得,而不是硬编码的IP地址和端口:
- 指向已知的Sentinel实例的ip:port对列表。
- 服务的名称,像”timelines”或者”cache”。
下面是客户端为了从Sentinel列表和服务名称获得主服务器地址而需要遵循的步骤。
第1步:连接第一个Sentinel(connecting to the first Sentinel)
客户端应该迭代Sentinel地址列表。应该尝试使用较短的
超时(大约几百毫秒)来连接到每一个地址的Sentinel。遇到
错误或者超时就尝试下一个Sentinel地址。
如果所有的Sentinel地址都没有尝试成功,就返回一个错误给客户端。
第一个回应客户端请求的Sentinel被置于列表的开头,这样在下次重连时,我们会首先尝试在上一次连接尝试是可达的Sentinel,以最小化延迟。
第2步:请求主服务器地址(ask for master address)
一旦与Sentinel的连接建立起来,客户端应该重新尝试在Sentinel上执行下面的命令:
class="java" name="code">SENTINEL get-master-addr-by-name master-name
这里的master-name应该被替换为用户指定的真实服务名称。
调用的结果可能是下面两种回复之一:
- ip:port对。
- 一个null回复。这表示Sentinel不知道这个主服务器。
如果收到了ip:port对,这个地址应该用来连接到Redis主服务器。否则,如果收到了一个null回复,客户端应该尝试列表中的下一个Sentinel。
第3步:在目标实例中调用ROLE命令(call the ROLE command in the target instance)
一旦客户端发现了主服务器实例的地址,就应该尝试与主服务器的连接,然后调用ROLE命令来验证实例的角色真的是一个主服务器。
如果ROLE命令不可用(Redis 2.8.12引进的),客户端可以使用INFO复制命令来
解析角色:输出中的某一个字段。
如果实例不是期待中的主服务器,客户端应该等待一小段时间(几百毫秒)然后再尝试从第1步开始。
处理重连(Handling reconnections)
一旦服务名称被解析为主服务器地址,并且与Redis主服务器实例的连接已经建立,每次需要重新连接时,客户端应该重新从第1步开始使用Sentinel来解析地址。例如,下面的情况下需要重新联系Sentinel:
- 如果客户端在超时或者socket错误后重连。
- 如果客户端因为被显式关闭或者被用户重连而重连。
在上面的情况下或者任何客户端丢失了与Redis服务器连接的情况下,客户端应该再次解析主服务器地址。
Sentinel故障转移断开(Sentinel failover disconnection)
从Redis 2.8.12开始,当Redis Sentinel改变了实例的配置,例如,提升从服务器为主服务器,故障转移后降级主服务器来复制新的主服务器,或者只是改变一个旧的(stale)从服务器的主服务器地址,会发送一个CLIENT KILL类型的命令给实例,来确保所有的客户端都与重新配置过的实例断开。这会强制客户端再次解析主服务器地址。
如果客户端要联系一个还未更新信息的Sentinel,通过ROLE命令验证Redis实例角色会失败,允许客户端发现联系上的Sentinel提供了旧的(stale)信息,然后会重试。
注意:一个旧的主服务器返回
在线的同时,客户端联系一个旧的Sentinel实例是有可能的,所以客户端可能连接了一个旧的主服务器,然而ROLE的输出也是匹配的。但是,当主服务器恢复回来以后,Sentinel将会尝试将其降级为从服务器,触发一次新的断开。这个逻辑也适用于连接到一个旧的从服务器,其会被重新配置来复制一个不同的主服务器。
连接从服务器(Connecting to slaves)
有时候客户端有兴趣连接到从服务器,例如,为了分离(scale)读请求。简单修改一下第2步就可以支持连接从服务器。不是调用下面的命令:
SENTINEL get-master-addr-by-name master-name
客户端应该调用:
SENTINEL slaves master-name
用于检索从服务器实例的清单。
相应地,客户端应该使用ROLE命令来验证实例真的是一个从服务器,以防止分离读请求到主服务器。
连接池(Connection pools)
对于实现了连接池的客户端,当单个连接重连时,应该要再次联系Sentinel,如果是主服务器的地址改变了,所有已经存在的连接都要关闭并且重新连接到新的地址。
错误报告(Error reporting)
客户端应该在遇到错误时正确的返回信息给用户,尤其是:
- 如果没有Sentinel能够联系上(这样客户端不可能从SENTINEL get-master-addr-by-name获得回复),应该返回明确表明Redis Sentinel不可达的错误。
- 如果所有池中的Sentinel返回null回复,用户必须被通知Sentinel不认识这个主服务器名称的错误。
Sentinel列表自动刷新(Sentinels list automatic refresh)
一旦收到get-master-addr-by-name的成功回复,客户端会按照下面的步骤来更新其内部的Sentinel节点的列表:
- 使用SENTINEL sentinels <master-name>命令获取这台主服务器的其他Sentinel列表。
- 添加每个不在列表中的ip:port对到列表的后面。
客户端不需要更新自己的配置文件来持久化列表。更新
内存中表示的Sentinel列表的能力对改进可靠性已经很有用了。
订阅Sentinel事件来改进响应能力(Subscribe to Sentinel events to improve responsiveness)
介绍Sentinel的文档中展示了客户端可以使用发布订阅来连接Sentinel以订阅Redis实例的配置变更。
这种机制可以用来加快客户端的重配置,也就是,客户端可以
监听发布订阅,以知道配置变更什么时候发生,从而运行上文解释的三步
协议来解析新的Redis主服务器(或者从服务器)地址。
但是,通过发布订阅收到的变更消息不能代替上面的步骤,因为不能保证客户端可以收到所有的变更消息。
额外信息(Additional information)
要获得额外信息或者讨论这个指引的特定方面,请发消息到Redis Google Group。
===============================================================================
大家好,我是阮威。华中科技大学,计算机软件专业硕士。
毕业后加入腾讯,先后在腾讯电子商务部和无线游戏产品部工作,现供职于欢聚时代基础产品部。IT男,至今。欢迎大家收听我的公众账号。