jinfeng_wang

G-G-S,D-D-U!

BlogJava 首页 新随笔 联系 聚合 管理
  400 Posts :: 0 Stories :: 296 Comments :: 0 Trackbacks
http://www.tuicool.com/articles/mA7beiM


最近在学习 Redis 的高可用方案,就从 sentinel 开始。本篇文档基本只是 redis sentinel 官方文档 的摘要和总结,感兴趣的直接阅读官方文档是更好的选择。

基本原理

Sentinel 的原理并不复杂:

  • 启动 n 个 sentinel 实例,这些 sentinel 实例会去监控你指定的 redis master/slaves
  • 当 redis master 节点挂掉后, Sentinel 实例通过 ping 检测失败发现这种情况就认为该节点进入 SDOWN 状态,也就是检测的 sentinel 实例主观地(Subjectively)认为该 redis master 节点挂掉。
  • 当一定数目(Quorum 参数设定)的 Sentinel 实例都认为该 master 挂掉的情况下,该节点将转换进入 ODOWN 状态,也就是客观地(Objectively)挂掉的状态。
  • 接下来 sentinel 实例之间发起选举,选择其中一个 sentinel 实例发起 failover 过程:从 slave 中选择一台作为新的 master,让其他 slave 从新的 master 复制数据,并通过 Pub/Sub 发布事件。
  • 使用者客户端从任意 Sentinel 实例获取 redis 配置信息,并监听(可选) Sentinel 发出的事件: SDOWN, ODOWN 以及 failover 等,并做相应主从切换,Sentinel 还扮演了服务发现的角色。
  • Sentinel 的 Leader 选举采用的是 Raft 协议 。

一张示意图,正常情况下:

当 M1 挂掉后:

节点 2 被提升为 master,Sentinel 通知客户端和 slaves 去使用新的 Master。

搭建实验环境

  • 两个 redis,一个主一个从,分别监听在 6379 和 6380 端口
$ redis-server $ redis-server --port 6380 
  • redis-cli -p 6380 连上 6380 端口的 redis,执行 slaveof 127.0.0.1 6379将它设置为 6379 的 slave。
  • 启动三个 sentinel 实例,分别监听在 5000 – 5002 端口,并且监控 6379 的 redis master,首先是配置文件

s1.conf:

port 5000 sentinel monitor mymaster 127.0.0.1 6370 2 sentinel down-after-milliseconds mymaster 1000 sentinel failover-timeout mymaster 60000 

其他两个配置文件是 s2.conf 和 s3.conf 只是将 port 5000 修改为 5001 和 5002,就不再重复。 需要确保配置文件是可写的,因为 Sentinel 会往配置文件里添加很多信息作为状态持久化,这是为了重启等情况下可以正确地恢复 sentinel 的状态。

启动:

$ redis-sentinel s1.conf $ redis-sentinel s2.conf $ redis-sentinel s3.conf 

配置说明:

  • port ,指定 sentinel 启动后监听的端口,sentinel 实例之间需要通过此端口通讯。
  • sentinel monitor [name] [ip] [port] [quorum] ,最重要的配置,指定要监控的 redis master 的 IP 和端口,给这个监控命名 name。Quorum 指定 至少 多少个 sentinel 实例对 redis master 挂掉的情况达成一致,只有达到这个数字后,Sentinel 才会去开始一次 failover 过程。
  • down-after-milliseconds,设定 Sentinel 发现一个 redis 没有响应 ping 到 Sentinel 认为该 redis 实例不可访问的时间。
  • failover-timeout,Sentinel 实例投票对于同一个 master 发起 failover 过程的间隔时间,防止同时开始多次 failover。

Sentinel 启动后会输出类似的日志:

17326:X 13 Oct 12:00:55.143 # +monitor master mymaster 127.0.0.1 6379 quorum 2 17326:X 13 Oct 12:00:55.143 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379 

表示开始监控 mymaster 集群,并输出集群的基本信息。

以及 Sentinel 之间的感知日志,比如 s3 节点的输出:

18441:X 13 Oct 12:01:39.985 * +sentinel sentinel eab05ac9fc34d8af6d59155caa195e0df5e80d73 127.0.0.1 5000 @ mymaster 127.0.0.1 6379 18441:X 13 Oct 12:01:52.918 * +sentinel sentinel 4bf24767144aea7b4d44a7253621cdd64cea6634 127.0.0.1 5002 @ mymaster 127.0.0.1 6379 

查看信息

可以用 redis-cli 连上 sentinel 实例,查看信息:

$ redis-cli -p 5000 127.0.0.1:5000> sentinel master mymaster  1) "name"  2) "mymaster"  3) "ip"  4) "127.0.0.1"  5) "port"  6) "6379"  7) "runid"  8) "4b97e168125b735e034d49c7b1f45925f43aded9"  9) "flags" 10) "master" 11) "link-pending-commands" 12) "0" 13) "link-refcount" 14) "1" 15) "last-ping-sent" 16) "0" 17) "last-ok-ping-reply" 18) "729" 19) "last-ping-reply" 20) "729" 21) "down-after-milliseconds" 22) "1000" 23) "info-refresh" 24) "6258" 25) "role-reported" 26) "master" 27) "role-reported-time" 28) "11853370" 29) "config-epoch" 30) "0" 31) "num-slaves" 32) "1" 33) "num-other-sentinels" 34) "2" 35) "quorum" 36) "2" 37) "failover-timeout" 38) "60000" 39) "parallel-syncs" 40) "1" 

sentinel master [name] 用于查看监控的某个 redis master 信息,包括配置和状态等,其他命令还包括:

  • sentinel masters 查看所有监控的 master 信息。
  • sentinel slaves [name] 查看监控的某个 redis 集群的所有 slave 节点信息。
  • sentinel sentinels [name] 查看所有 sentinel 实例信息。

更重要的一个命令是根据名称来查询 redis 信息,客户端会用到:

127.0.0.1:5000> SENTINEL get-master-addr-by-name mymaster 1) "127.0.0.1" 2) "6379" 

测试 Failover

我们让 6379 的 master 主动休眠 30 秒来观察 failover 过程:

$ redis-cli -p 6379 DEBUG sleep 30 

我们可以看到每个 sentinel 进程都监控到 master 挂掉,从 sdown 状态进入 odown,然后选举了一个 leader 来进行 failover,最终 6380 成为新的 master, sentinel 的日志输出:

18441:X 13 Oct 15:26:51.735 # +sdown master mymaster 127.0.0.1 6379 18441:X 13 Oct 15:26:51.899 # +new-epoch 1 18441:X 13 Oct 15:26:51.900 # +vote-for-leader eab05ac9fc34d8af6d59155caa195e0df5e80d73 1 18441:X 13 Oct 15:26:52.854 # +odown master mymaster 127.0.0.1 6379 #quorum 3/2 18441:X 13 Oct 15:26:52.854 # Next failover delay: I will not start a failover before Thu Oct 13 15:28:52 2016 18441:X 13 Oct 15:26:53.034 # +config-update-from sentinel eab05ac9fc34d8af6d59155caa195e0df5e80d73 127.0.0.1 5000 @ mymaster 127.0.0.1 6379 18441:X 13 Oct 15:26:53.034 # +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6380 18441:X 13 Oct 15:26:53.034 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380 18441:X 13 Oct 15:26:54.045 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380 18441:X 13 Oct 15:27:20.383 # -sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380 

日志的几个主要事件:

  • +sdown master mymaster 127.0.0.1 6379 ,发现 master 检测失败,主观认为该节点挂掉,进入 sdown 状态。
  • +odown master mymaster 127.0.0.1 6379 #quorum 3/2 ,有两个 sentinel 节点认为 master 6379 挂掉,达到配置的 quorum 值 2,因此认为 master 已经客观挂掉,进入 odown 状态。
  • +vote-for-leader eab05ac9fc34d8af6d59155caa195e0df5e80d73 准备选举一个 sentinel leader 来开始 failover。
  • +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6380 切换 master 节点, failover 完成。
  • +config-update-from sentinel eab05ac9fc34d8af6d59155caa195e0df5e80d73 127.0.0.1 5000 @ mymaster 127.0.0.1 6379 更新 sentinel 配置。
  • 6379 休眠回来,作为 slave 挂载到 6380 后面,可见 sentinel 确实同时在监控 slave 状态,并且挂掉的节点不会自动移除,而是继续监控。

此时查看 sentinel 配置文件,会发现增加了一些内容:

# Generated by CONFIG REWRITE dir "/Users/dennis/opensources/redis-sentinel" sentinel failover-timeout mymaster 60000 sentinel config-epoch mymaster 1 sentinel leader-epoch mymaster 1 sentinel known-slave mymaster 127.0.0.1 6379 sentinel known-sentinel mymaster 127.0.0.1 5001 8ba1e75cbf4c268be4a2950ee7389df746c6b0b4 sentinel known-sentinel mymaster 127.0.0.1 5002 4bf24767144aea7b4d44a7253621cdd64cea6634 sentinel current-epoch 1 

可以看到 sentinel 将最新的集群状态写入了配置文件。

运维

命令

除了上面提到的一些查看信息的命令之外, sentinel 还支持下列命令来管理和检测 sentinel 配置:

  • SENTINEL reset <pattern> 强制重设所有监控的 master 状态,清除已知的 slave 和 sentinel 实例信息,重新获取并生成配置文件。
  • SENTINEL failover <master name> 强制发起一次某个 master 的 failover,如果该 master 不可访问的话。
  • SENTINEL ckquorum <master name> 检测 sentinel 配置是否合理, failover 的条件是否可能满足,主要用来检测你的 sentinel 配置是否正常。
  • SENTINEL flushconfig 强制 sentinel 重写所有配置信息到配置文件。

增加和移除监控以及修改配置参数:

  • SENTINEL MONITOR <name> <ip> <port> <quorum>
  • SENTINEL REMOVE <name>
  • SENTINEL SET <name> <option> <value>

增加和移除 Sentinel

增加新的 Sentinel 实例非常简单,修改好配置文件,启动即可,其他 Sentinel 会自动发现该实例并加入集群。如果要批量启动一批 Sentinel 节点,最好以 30 秒的间隔一个一个启动为好,这样能确保整个 Sentinel 集群的大多数能够及时感知到新节点,满足当时可能发生的选举条件。

移除一个 sentinel 实例会相对麻烦一些,因为 sentinel 不会忘记已经感知到的 sentinel 实例,所以最好按照下列步骤来处理:

  • 停止将要移除的 sentinel 进程。
  • 给其余的 sentinel 进程发送 SENTINEL RESET * 命令来重置状态,忘记将要移除的 sentinel,每个进程之间间隔 30 秒。
  • 确保所有 sentinel 对于当前存货的 sentinel 数量达成一致,可以通过 SENTINEL MASTER [mastername] 命令来观察,或者查看配置文件。

客户端实现

客户端从过去直接连接 redis ,变成:

  1. 先连接一个 sentinel 实例
  2. 使用 SENTINEL get-master-addr-by-name master-name 获取 redis 地址信息。
  3. 连接返回的 redis 地址信息,通过 ROLE 命令查询是否是 master。如果是,连接进入正常的服务环节。否则应该断开重新查询。
  4. (可选)客户端可以通过 SENTINEL sentinels [name] 来更新自己的 sentinel 实例列表。

当 Sentinel 发起 failover 后,切换了新的 master,sentinel 会发送 CLIENT KILL TYPE normal 命令给客户端,客户端需要主动断开对老的master 的链接,然后重新查询新的 master 地址,再重复走上面的流程。这样的方式仍然相对不够实时,可以通过 sentinel 提供的 Pub/Sub 来更快地监听到 failover 事件,加快重连。

如果需要实现读写分离,读走 slave,那可以走 SENTINEL slaves [name] 来查询 slave 列表并连接。

生产环境推荐

对于一个最小集群,Redis 应该是一个 master 带上两个 slave,并且开启下列选项:

min-slaves-to-write 1 min-slaves-max-lag 10 

这样能保证写入 master 的同时至少写入一个 slave,如果出现网络分区阻隔并发生 failover 的时候,可以保证写入的数据最终一致而不是丢失,写入老的 master 会直接失败,参考 Consistency under partitions 。

Slave 可以适当设置优先级,除了 0 之外(0 表示永远不提升为 master),越小的优先级,越有可能被提示为 master。如果 slave 分布在多个机房,可以考虑将和 master 同一个机房的 slave 的优先级设置的更低以提升他被选为新的 master 的可能性。

考虑到可用性和选举的需要,Sentinel 进程至少为 3 个,推荐为 5 个,如果有网络分区,应当适当分布(比如 2 个在 A 机房, 2 个在 B 机房,一个在 C 机房)等。

其他

由于 Redis 是异步复制,所以 sentinel 其实无法达到强一致性,它承诺的是最终一致性:最后一次 failover 的 redis master 赢者通吃,其他slave 的数据将被丢弃,重新从新的 master 复制数据。此外还有前面提到的分区带来的一致性问题。

其次,Sentinel 的选举算法依赖时间,因此要确保所有机器的时间同步,如果发现时间不一致,Sentinel 实现了一个 TITL 模式来保护系统的可用性。

posted on 2016-12-14 18:25 jinfeng_wang 阅读(170) 评论(0)  编辑  收藏 所属分类: 2016-REDIS

只有注册用户登录后才能发表评论。


网站导航:
博客园   IT新闻   Chat2DB   C++博客   博问