redis 学习笔记(4)-HA高可用方案Sentinel配置

转载自:http://www.cnblogs.com/yjmyzz/p/redis-sentinel-sample.htmlhtml

上一节中介绍了master-slave模式, 在最小配置:master、slave各一个节点的状况下,不论是master仍是slave down掉一个,“完整的”读/写功能都将受影响,这在生产环境中显然不能接受。幸亏redis提供了sentinel(哨兵)机制,经过 sentinel模式启动redis后,自动监控master/slave的运行状态,基本原理是:心跳机制+投票裁决redis

每一个sentinel会向其它sentinal、master、slave定时发送消息,以确认对方是否“活”着,若是发现对方在指定时间(可配置)内未回应,则暂时认为对方已挂(所谓的“主观认为宕机” Subjective Down,简称SDOWN)。算法

若“哨兵群”中的多数sentinel,都报告某一master没响应,系统才认为该master"完全死亡"(即:客观上的真正down 机,Objective Down,简称ODOWN),经过必定的vote算法,从剩下的slave节点中,选一台提高为master,而后自动修改相关配置。spring

 

 

最小化的sentinel配置文件为:缓存

port 7031

dir /opt/app/redis/redis-2.8.17/tmp

sentinel monitor mymaster 10.6.144.155 7030 1
sentinel down-after-milliseconds mymaster 5000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 15000

第1行,指定sentinel使用的端口,不能与redis-server运行实例的端口冲突app

第3行,指定工做目录运维

第5行,显示监控master节点10.6.144.155,master节点使用端口7030,最后一个数字表示投票须要的"最少法定人数",比 若有10个sentinal哨兵都在监控某一个master节点,若是须要至少6个哨兵发现master挂掉后,才认为master真正down掉,那么 这里就配置为6,最小配置1台master,1台slave,在二个机器上都启动sentinal的状况下,哨兵数只有2个,若是一台机器物理挂掉,只剩 一个sentinal能发现该问题,因此这里配置成1,至于mymaster只是一个名字,能够随便起,但要保证5-8行都使用同一个名字测试

第6行,表示若是5s内mymaster没响应,就认为SDOWN优化

第8行,表示若是15秒后,mysater仍没活过来,则启动failover,从剩下的slave中选一个升级为masterspa

第7行,表示若是master从新选出来后,其它slave节点能同时并行重新master同步缓存的台数有多少个,显然该值越大,全部slave 节点完成同步切换的总体速度越快,但若是此时正好有人在访问这些slave,可能形成读取失败,影响面会更广。最保定的设置为1,只同一时间,只能有一台 干这件事,这样其它slave还能继续服务,可是全部slave所有完成缓存更新同步的进程将变慢。

另:一个sentinal可同时监控多个master,只要把5-8行重复多段,加以修改便可。

 

具体使用步骤:(约定7030是redis-server端口,7031是redis-sentinel端口,且master、slave上的redis-server均已正常启动)

一、先在redis根目录下建立conf子目录,新建配置文件sentinel.conf,内容参考前面的内容(master和slave上都作相同的配置)

二、./redis-sentinel ../conf/sentinel.conf 便可(master和slave上都启用sentinel,即最终有二个哨兵)

三、./redis-cli -p 7031 sentinel masters 可经过该命令查看当前的master节点状况(注,这里必定要带sentinel的端口)

四、在master上,./redis-cli -p 7030 shutdown ,手动把master停掉,观察sentinel的输出

[17569] 21 Nov 11:06:56.277 # +odown master mymaster 10.6.144.155 7030 #quorum 1/1
[17569] 21 Nov 11:06:56.277 # Next failover delay: I will not start a failover before Fri Nov 21 11:07:26 2014
[17569] 21 Nov 11:06:57.389 # +config-update-from sentinel 10.6.144.156:7031 10.6.144.156 7031 @ mymaster 10.6.144.155 7030
[17569] 21 Nov 11:06:57.389 # +switch-master mymaster 10.6.144.155 7030 10.6.144.156 7030
[17569] 21 Nov 11:06:57.389 * +slave slave 10.6.53.131:7030 10.6.53.131 7030 @ mymaster 10.6.144.156 7030

从红线部分能够看出,master发生了迁移,等刚才停掉的master再重启后,能够观察到它将被看成slave加入,相似如下输出:

[36444] 21 Nov 11:11:14.540 * +convert-to-slave slave 10.6.144.155:7030 10.6.144.155 7030 @ mymaster 10.6.144.156 7030

注意事项:发生master迁移后,若是遇到运维须要,想重启全部redis,必须最早重启“新的”master节点,不然sentinel会一直找不到master。

最后,若是想中止sentinel,可输入命令./redis-cli -p 7031 shutdown

 

客户端的使用:

1、Jedis

@Test
    public void testJedis() throws InterruptedException {

        Set<String> sentinels = new HashSet<String>();
        sentinels.add("10.6.144.155:7031");
        sentinels.add("10.6.144.156:7031");        

        JedisSentinelPool sentinelPool = new JedisSentinelPool("mymaster",
                sentinels);

        Jedis jedis = sentinelPool.getResource();

        System.out.println("current Host:"
                + sentinelPool.getCurrentHostMaster());

        String key = "a";

        String cacheData = jedis.get(key);

        if (cacheData == null) {
            jedis.del(key);
        }

        jedis.set(key, "aaa");// 写入

        System.out.println(jedis.get(key));// 读取

        System.out.println("current Host:"
                + sentinelPool.getCurrentHostMaster());// down掉master,观察slave是否被提高为master

        jedis.set(key, "bbb");// 测试新master的写入

        System.out.println(jedis.get(key));// 观察读取是否正常

        sentinelPool.close();
        jedis.close();

    }

4-6行是关键,这里指定了sentinel节点信息。但这段代码在运行时发现一个问题:对于1主1从的最小化配置,若是连续发生两次写操做,第1 次set成功后,若是断点停在这里,down掉master,这时剩下的slave会提高为master,可是第2次set时,会抛异常,相似:链接已断 开。(经过Spring-Data-Redis整合Jedis与redis时,利用RedisTemplate调用不会有这个问题,看来Spring-Data-Redis针对这个问题作过优化,因此建议正式项目中,经过Spring-Data-Redis整合Redis来调用相关功能,而不是本身直接引用Jedis的jar包来使用)

 

2、Redisson

@Test
    public void testRedisson() throws InterruptedException, ExecutionException,
            TimeoutException {

        Config config = new Config();

        config.useSentinelConnection().setMasterName("mymaster")
                .addSentinelAddress("10.6.144.155:7031", "10.6.144.156:7031");
        config.useSentinelConnection().setRetryInterval(1000);
        config.useSentinelConnection().setRetryAttempts(1);

        Redisson redisson = Redisson.create(config);

        String key = "test";

        RBucket<String> myObj = redisson.getBucket(key);
        if (myObj != null) {
            myObj.delete();
        }

        myObj.set("aaa");// 写入

        System.out.println(myObj.get());// 读取

        myObj.set("bbb");// down掉master,观察是否能写入新master

        System.out.println(myObj.get());

        redisson.shutdown();

    }

一样作相似的测试,二次写,二次读,若是第1次写后,人工down掉master,剩下的slave会提高成master,第二次写ok,但此时 redis节点中,只剩master,没有slave了,从测试结果上看,第二次get仍是尝试去找slave节点,可是此时已经不存在了,因此一直在等 候,致使后面的的处理被阻塞。

这不是redis的问题,而是Redisson客户端设计不够智能。

鉴于这种现状,若是要使用Redisson,最好作成1主2从的部署结构:(sentinel.conf中的“法定人数”,建议调整成2)

 

这样的好处是,1个master挂掉后,剩下的2台slave中,会有1台提高为master,总体仍然保证有1个master和1个slave,读写均不受影响。

关于Sentinel的更多细节,可参考官网文档:http://www.redis.io/topics/sentinel

相关文章
相关标签/搜索