天天看点

Redis Sentinel一、Redis Sentinel 架构二、Redis Sentinel 故障转移三、Redis Sentinel 配置与安装四、使用客户端连接redis sentinel 五、三个定时任务六、其他

主从技术的切换方法是:当主节点宕机后,需要人工将从节点切换为主节点,这样的方式费事费力还会造成一段时间内服务不可用,这样的方式显然不是我们需要的,所以我们必须要有一个高可用的方案来抵抗节点的故障,当节点发生故障时可以自动进行主从切换,程序可以不用重启,仿佛什么事情都没有发生一样。Redis官方提供了这样一种方案-——Redis Sentinel(Sentinel的含义是哨兵)。

一、Redis Sentinel 架构

Redis Sentinel一、Redis Sentinel 架构二、Redis Sentinel 故障转移三、Redis Sentinel 配置与安装四、使用客户端连接redis sentinel 五、三个定时任务六、其他

如上图所示,我们可以将Redis Sentinel 集群看成是一个zookeeper集群,它是集群高可用的心脏,一般有3~5个节点组成,这样即使个别节点挂了,集群还可以正常运转。

Sentinel 负责监控主从节点的健康,当主节点挂掉时自动选择一个最优的从节点切换为主节点。当客户端来连接集群时会首先连接Sentinel,通过Sentinel来查询主节点的地址,然后再连接主节点进行数据交互。当主节点发生故障时,客户端会重新向Sentinel要地址,Sentinel会将最新的主节点地址告诉客户端,如此应用将无须重新启动就可以自动完成节点切换。

二、Redis Sentinel 故障转移

Redis Sentinel一、Redis Sentinel 架构二、Redis Sentinel 故障转移三、Redis Sentinel 配置与安装四、使用客户端连接redis sentinel 五、三个定时任务六、其他

如上图所示,如果主节点挂掉了,原先的主从复制也断开了,一个从节点被提升为新的主节点,其他的从节点开始和新的主节点建立复制关系。客户端通过新的主节点继续进行交互,Sentinel会持续监听已经挂掉的主节点,待它恢变成从节点,从新的主节点哪里建立 复制关系。

故障转移可以概括为下面的几个步骤:

  1.  当多个sentinel发现master有问题会选举出一个sentinel为领导。
  2. 被选为领导的sentinel会选择出一个slave为新的master。
  3. 通知其余的slave成为新的master的slave。
  4. 通知客户端新的master的地址
  5. 等待原来的master复活成为新master的slave。

三、Redis Sentinel 配置与安装

1. redis 主节点

Redis Sentinel一、Redis Sentinel 架构二、Redis Sentinel 故障转移三、Redis Sentinel 配置与安装四、使用客户端连接redis sentinel 五、三个定时任务六、其他

2. redis从节点

Redis Sentinel一、Redis Sentinel 架构二、Redis Sentinel 故障转移三、Redis Sentinel 配置与安装四、使用客户端连接redis sentinel 五、三个定时任务六、其他

3. sentinel配置

Redis Sentinel一、Redis Sentinel 架构二、Redis Sentinel 故障转移三、Redis Sentinel 配置与安装四、使用客户端连接redis sentinel 五、三个定时任务六、其他

配置说明:

  • port: 端口号
  • dir:工作目录
  • logfile:日志
  • sentinel monitor mymaster 127.0.0.1 7000 2 :mymaster代表的是master的名字,127.0.0.1 7000代表的是master的ip和端口,2代表的是至少有多少个sentinel发现master是有问题的才会进行下一步的故障转移
  • sentinel down-after-milliseconds mymaster 3000:sentinel对master的进行一个判断,如果超过规定的时间master还没有响应就代表master是有问题的,这里是30000毫秒。
  • sentinel parallel-syncs mymaster 1:老的slave对新的master复制同时是串行的还是并发的,这里的1 代表每次只能复制一个。
  • sentinel failover-timeout mymastere 180000:故障转移的时间

四、使用客户端连接redis sentinel

1. 客户端实现基本原理

a. 客户端遍历sentinel节点集合获取一个可用的sentinel节点

Redis Sentinel一、Redis Sentinel 架构二、Redis Sentinel 故障转移三、Redis Sentinel 配置与安装四、使用客户端连接redis sentinel 五、三个定时任务六、其他

b. 对可用sentinel获取master节点的名字、地址和端口

Redis Sentinel一、Redis Sentinel 架构二、Redis Sentinel 故障转移三、Redis Sentinel 配置与安装四、使用客户端连接redis sentinel 五、三个定时任务六、其他

c. 获取到master节点后使用role/role application验证是否是真正的master

Redis Sentinel一、Redis Sentinel 架构二、Redis Sentinel 故障转移三、Redis Sentinel 配置与安装四、使用客户端连接redis sentinel 五、三个定时任务六、其他

d. 当master发生变化时通知客户端

Redis Sentinel一、Redis Sentinel 架构二、Redis Sentinel 故障转移三、Redis Sentinel 配置与安装四、使用客户端连接redis sentinel 五、三个定时任务六、其他

2.jedis

public class TestSentinel {
    @SuppressWarnings("resource")
    @Test
    public void testSentinel() {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(10);
        jedisPoolConfig.setMaxIdle(5);
        jedisPoolConfig.setMinIdle(5);
        // 哨兵信息
        Set<String> sentinels = new HashSet<>(Arrays.asList("192.168.11.128:26379",
                "192.168.11.129:26379","192.168.11.130:26379"));
        // 创建连接池
        JedisSentinelPool pool = new JedisSentinelPool("mymaster", sentinels,jedisPoolConfig,"123456");
        // 获取客户端
        Jedis jedis = pool.getResource();
        // 执行两个命令
        jedis.set("mykey", "myvalue");
        String value = jedis.get("mykey");
        System.out.println(value);
    }
}
           

3. 通过spring进行配置

<bean id = "poolConfig" class="redis.clients.jedis.JedisPoolConfig">
            <!-- 最大空闲数 -->
            <property name="maxIdle" value="50"></property>
            <!-- 最大连接数 -->
            <property name="maxTotal" value="100"></property>
            <!-- 最大等待时间 -->
            <property name="maxWaitMillis" value="20000"></property>
        </bean>
        
        <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
            <constructor-arg name="poolConfig" ref="poolConfig"></constructor-arg>
            <constructor-arg name="sentinelConfig" ref="sentinelConfig"></constructor-arg>
            <property name="password" value="123456"></property>
        </bean>
        
        <!-- JDK序列化器 -->
        <bean id="jdkSerializationRedisSerializer" class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"></bean>
        
        <!-- String序列化器 -->
        <bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean>
        
        <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
            <property name="connectionFactory" ref="connectionFactory"></property>
            <property name="keySerializer" ref="stringRedisSerializer"></property>
            <property name="defaultSerializer" ref="stringRedisSerializer"></property>
            <property name="valueSerializer" ref="jdkSerializationRedisSerializer"></property>
        </bean>
        
        <!-- 哨兵配置 -->
        <bean id="sentinelConfig" class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
            <!-- 服务名称 -->
            <property name="master">
                <bean class="org.springframework.data.redis.connection.RedisNode">
                    <property name="name" value="mymaster"></property>
                </bean>
            </property>
            <!-- 哨兵服务IP和端口 -->
            <property name="sentinels">
                <set>
                    <bean class="org.springframework.data.redis.connection.RedisNode">
                        <constructor-arg name="host" value="192.168.11.128"></constructor-arg>
                        <constructor-arg name="port" value="26379"></constructor-arg>
                    </bean>
                    <bean class="org.springframework.data.redis.connection.RedisNode">
                        <constructor-arg name="host" value="192.168.11.129"></constructor-arg>
                        <constructor-arg name="port" value="26379"></constructor-arg>
                    </bean>
                    <bean class="org.springframework.data.redis.connection.RedisNode">
                        <constructor-arg name="host" value="192.168.11.130"></constructor-arg>
                        <constructor-arg name="port" value="26379"></constructor-arg>
                    </bean>
                </set>
            </property>
        </bean>
           

 五、三个定时任务

为了保证可以为redis进行故障转移,redis sentinel内部有三个定时任务

1. 每10秒每个sentinel对master和slave执行info

这个定时任务的主要目的如下:

  • 发现slave节点:在配置中并没有配置slave节点的信息,实际上是不需要的配置的 ,sentinel会对master执行info操作,会在info replication 中发现slave信息从而发现slave节点。
  • 确认主从关系:对每个执行info就可以确认他们之前的关系和关系的变化。

2.每2秒每个sentinel通过master节点的channel交换信息(pub/sub)

mster节点上会有一个发布订阅的channel(频道)用于让sentinel节点进行信息交换利用的原理就是每个sentinel发布信息,其他的sentinel可以收到信息(信息中会包含当前自身的信息、master的信息和对master和slave的判断),最后sentinel之间会达成一个共识,他们之前的信息交换是利用的master的 channel,利用的是发布订阅。

这个定时任务的主要目的如下:

  • 通过_sentinel_:hello频道交互
  • 交互对节点的看法和自身的信息

3.每1秒每个sentinel对其他的sentinel执行和redis执行ping

这个定时任务的主要目的如下:

  • 心跳检测,失败判断的依据

六、其他

1. 主观下线和可观下线

  • 主观下线:每个sentinel节点对节点失败的偏见
  • 客观下线:所有sentinel对节点的失败达成共识

2.领导者选择

  • 原因:只有一个sentinel完成故障转移
  • 选举:通过sentinel is-master-down-by-addr 命令都希望成为领导者

选举过程如下:

  1. 每个主观下线的sentinel向其他sentinel发送命令,要求将他设置为领导者。
  2. 收到命令的sentinel节点如果没有同意通过其他sentinel节点发送的命令,那么将同意该请求否则拒绝。
  3. 如果该sentinel节点发现自己已经超过sentinel集合的半数并且超过 sentinel monitor这个配置中所设置的数量,那么它将成为领导者。
  4. 如果此过程有多个sentinel成为领导者,那么将等待一段时间再次选举。

3.故障转移

故障转移有如下几个步骤:

  1. 从slave节点选出一个“合适”的节点作为新的matser
  2. 对上面的slave节点执行 slaveof no one 命令让其成为master节点。
  3. 向剩余的slave节点发送命令,让他们成为新master节点的slave节点,复制规则和parallel-sync参数有关
  4. 更新对原来master节点配置为slave,并保持着对其关注,当其恢复后命令它去复制新的master节点。

什么是合适的slave节点?

  • 选择 save-priority(slave节点优先级)最高的slave节点,如果存在则返回,不存在则继续。
  • 选择复制偏移量最大的slave节点(复制的最完整),如果存在则返回,不存在则继续。
  • 选择runId最小的slave节点

4.消息丢失

Redis主从采用异步复制,意味着主节点挂掉时,从节点可能没有收到全部的同步消息,这部分未同步的消息就丢失了,如果主从延迟特别大,那么丢失的数据就可能会特别多。Sentinel无法保证数据不丢失,但也能保证消息少丢失,它有两个选项可以限制主从延迟过大。

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

第一个参数表示主节点必须至少有一个从节点在进行正常复制,否则就停止对外写服务,丧失可用性。

第二个参数控制什么是正常复制,什么是异常复制,它的单位是秒(s),表示如果在10s没有收到从节点反馈,就意味着从节点同步不正常,要么是网络断开了,要么是一直没有给反馈。

继续阅读