Redis高可用主要有网络层面的keepalived,注册中心的zookeeper,这两种方案,这两种方案,第一种方案浪费掉了一台,第二种方案,工作成本相当高。本文介绍使用sentinel做redis高可用方案设计。

Redis Sentinel

Sentinel

sentinel是Redis官方为集群提供的高可用的解决方案,在实际项目中是使用sentinel做redis自动故障转移。同时也增加了监控消息的通知,这样客户端就可以根据消息类型去判断服务器的状态,做适配操作。

Sentinel功能列表

  1. Monitoring 这是Sentinel中持续检查集群中的master,slave状态,用于判断是否存活的。
  2. Notification 在发现redis死亡以后,执行的脚本。
  3. Automatic failover 故障转移脚本
  4. Configuration provider 保存可信赖的当前master地址。

Sentinel配置

Sentinel本质上是一个特殊模式下的redis服务器。通过不同配置区分提供服务。

sentinel.conf 配置

// [监控名称] [ip] [port] [多少sentinel同意才发生故障转移]
sentinel monitor mymaster 127.0.0.1 6379 2
// [监控名称] [Master多少毫秒后不回应ping命令,就认为master是主观下线状态]

sentinel down-after-milliseconds mymaster 60000</pre>

// [故障转移超时时间]

sentinel failover-timeout mymaster 180000

//[在执行故障转移时,最多可以有多少个从服务器同时对新的主服务器进行同步]

sentinel parallel-syncs mymaster 1

启动命令

redis-sentinel sentinel.conf

启动后Sentinel会:

以10秒一次的频率,向被监视的master发送info命令,根据回复获取master当前信息。
以1秒一次的频率,向所有redis服务器、包含sentinel在内发送PING命令,通过回复判断服务器是否在线。
以2秒一次的频率,通过向所有被监视的master,slave服务器发送包含当前sentinel,master信息的消息。

故障转移三种消息接收方式

当Redis服务器发现故障以后,sentinel通过raft算法投票选举新的master,故障转移过程通过哨兵的api获取/订阅接收事件消息

脚本接收

即,代执行脚本

//当故障转移期间,可以指定一个“通知”脚本用来告知系统管理员,当前集群的情况。
//脚本被允许执行的最大时间为60秒,如果超时,脚本将会被终止(KILL)

sentinel notification-script mymaster /var/redis/notify.sh 
复制代码
//故障转移期之后,配置通知客户端的脚本.

sentinel client-reconfig-script mymaster /var/redis/notifyReconfig.sh 

客户端直接接收

使用发布订阅模式实现
Sentinel的故障转移消息通知使用的是Redis的发布订阅模式,即,在故障转移期间所有产生的事件信息,都会通过频道发布出去,例如我们加一台slave服务,sentinel监听到后会发布加slave消息到+slave频道上,客户端只需要订阅+slave频道即可接收到对应的消息。
消息格式如下

[实例类型] [事件服务器名称] [服务器ip] [服务器端口] @[master名称] [ip] [端口]
<instance-type> <name> <ip> <port> @ <master-name> <master-ip> <master-port>

通知消息格式如下

*          //订阅类型, *即订阅所有事件消息。
-sdown     //消息类型
slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6381

订阅消息格式

using (RedisSentinel rs = new RedisSentinel(CurrentNode.Host, CurrentNode.Port))
            {
                var redisPubSub = new RedisPubSub(node.Host, node.Port);
                redisPubSub.OnMessage += OnMessage;
                redisPubSub.OnSuccess += (msg) =>{};
                redisPubSub.OnUnSubscribe += (obj) =>{};
                redisPubSub.OnError = (exception) =>{ };
                redisPubSub.PSubscribe("*");
            }

服务间接收

这种方式在第二种基础上扩展了一层,应用不需要直接订阅sentinel,单独空余出服务去做,添加api来做。
例如:
应用端提供回调api,在api逻辑下刷新内存中的redis连接

http://127.0.0.1/redis/notify.api

监控到异常以后,进行调用

 httprequest.post("http://127.0.0/redis/notify.api");

整体设计

整体设计如下
巧用 | 低成本高可用,巧用Redis插图