redis主备哨兵2

redis 学习笔记(3)-master/slave(主/从模式)

类似mysql的master-slave模式一样,redis的master-slave可以提升系统的可用性,master节点写入cache后,会自动同步到slave上。

环境:

master node: 10.6.144.155:7030

slave node: 10.6.144.156:7031

 

一、配置

仅需要在slave node上修改配置:

找到slaveof这行,参考下面的修改(填上master node的Ip和端口就完事了)

slaveof 10.6.144.155 7030

另外注意下 slave-read-only yes 这行,这表示slave只读不写,也是推荐设置

 

二、验证

启动master/slave这二台机器上的redis,在master上加一个缓存项

然后在slave上取出该缓存项

取到了,说明master上的cache自动复制到slave节点了

 

三、redisson客户端使用

  View Code

注:经实际测试,redisson客户端在set写操作时,连接的是master node,get读操作时连接的是slave,而且遇到操作失败,会同步阻塞后面的处理(一直等待,直到超时)

即:set操作时,至少要有一台可连接的master,get操作时,至少要有一台可连接的slave

 

四、Jedis客户端使用

  View Code

 

后记:个人感觉master-slave模式作用有限,因为从二种client的测试结果看,在没有其它监控机制的前提下,无论是master或slave挂掉,都需要手动调整配置或修改代码,才能保证读/写继续正常工作,理想情况是master挂掉,最好slave中能自动(无需人工干预)选出一台充当master继续服务。redis 的cluster功能,目前尚处于beta阶段,估计不久的将来,等cluster功能正式发布后,可以通过custer功能搭建redis集群。



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

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

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

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

 

 

最小化的sentinel配置文件为:

复制代码
1 port 7031
2 
3 dir /opt/app/redis/redis-2.8.17/tmp
4 
5 sentinel monitor mymaster 10.6.144.155 7030 1
6 sentinel down-after-milliseconds mymaster 5000
7 sentinel parallel-syncs mymaster 1
8 sentinel failover-timeout mymaster 15000
复制代码

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

第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中选一个升级为master

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

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

 

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

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

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

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

4、在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

 

客户端的使用:

一、Jedis

  View Code

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包来使用)

 

二、Redisson

  View Code

同样做类似的测试,二次写,二次读,如果第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

redis 学习笔记(5)-Spring与Jedis的集成

首先不得不服Spring这个宇宙无敌的开源框架,几乎整合了所有流行的其它框架,http://projects.spring.io/spring-data/ 从这上面看,当下流行的redis、solr、hadoop、mongoDB、couchBase... 全都收入囊中。对于redis整合而言,主要用到的是spring-data-redis

使用步骤:

一、pom添加依赖项

        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>1.4.1.RELEASE</version>
        </dependency>

其它Spring必备组件,比如Core,Beans之类,大家自行添加吧

观察一下:

jedis、jredis等常用java的redis client已经支持了,不知道以后会不会集成Redisson,spring-data-redis提供了一个非常有用的类:StringRedisTemplate

对于大多数缓存应用场景而言,字符串是最常用的缓存项,用StringRedisTemplate可以轻松应付。

 

二、spring配置

  View Code

提示:上面配置中的端口为sentinel的端口,而非redis-server的端口。

这里我们使用Sentinel模式来配置redis连接,从上篇学习知道,sentinel是一种高可用架构,个人推荐在生产环境中使用sentinel模式。

注:26-28行,经试验,如果修改了默认端口,这里必须明细指定hostName及port,否则运行后,无法正确读写缓存,参考下面的配置:

(2016-4-2更新:最新1.6.4版的spring-data-redis 已经修正了这个问题,无需再指定端口和hostname)

复制代码
    <bean id="jedisConnFactory"
          class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <property name="hostName" value="10.6.53.xxx"/>
        <property name="port" value="8830"/>
        <property name="usePool" value="false"/>
        <constructor-arg ref="redisSentinelConfiguration"/>
    </bean>
复制代码

其中hostName为当前master的IP,port为redis-server的运行端口(非sentinel端口),此外还要设置usePool为false,由于sentinel可能会自行切换master节点,如果不清楚当前的master节点是哪台机器,可以用前面提到的命令./redis-cli -p <sentinal端口号> sentinel masters查看,或者用java代码输出,参考下面的代码:

1         ApplicationContext ctx = new FileSystemXmlApplicationContext("/opt/app/spring-redis.xml");
2         StringRedisTemplate template = ctx.getBean(StringRedisTemplate.class);
3         for (RedisServer m : template.getConnectionFactory().getSentinelConnection().masters()) {
4             logger.debug(m);
5         }

另外<property name="usePool" value="false"/> 这里的value值如果改成true,经实际测试,发现偶尔会报如下错误(如果报错,换成false通常就可以了):

redis.clients.jedis.exceptions.JedisDataException: ERR unknown command 'SET'

其它注意事项:

配置文件中的sentinels属性的Set 中的节点,并非一定要在同一个master下,也可以是归属于多个master,即:如果这里配置了10个node信息,其中1-3归属于master1,剩下的4-10属于master2,这也是允许的。

这样调用时,通过StringRedisTemplate.getConnectionFactory().getSentinelConnection().masters()可以返回一个master的列表,然后代码中根据需要,向某一个需要的master写入缓存.

 

三、单元测试

  View Code

运行一下,行云流水般的输出:

...

信息: Created JedisPool to master at 10.6.144.***:7030
http://yjmyzz.cnblogs.com/
---------------
0
A
B
---------------
C
B
A
---------------
SHA - 上海虹桥
PVG - 浦东
PEK - 北京
---------------

...

注意红色标出部分,从eclipse控制台的输出,还能看出当前的master是哪台服务器

这里再补充一点小技巧:如果想遍历所有master及slave可以参考以下代码

  View Code

输出类似下面的结果:

master => 172.20.16.191:6379
slaves of 172.20.16.191:6379 => 172.20.16.192:6379

注:这里输出的slaves列表,经实际测试,发现只是根据redis server端的配置呆板的返回slave node列表,不管这些node是死是活,换句话说,就算某个slave已经down掉,这里依然会返回。

 

三、POJO对象的缓存

Spring提供的StringRedisTemplate只能对String操作,大多数情况下已经够用,但如果真需要向redis中存放POJO对象也不难,我们可以参考StringRedisTemplate的源码,扩展出ObjectRedisTemplate

  View Code

然后就可以这样用了:

  View Code

其中SampleBean的定义如下:

  View Code

注:由于不是标准的String类型,所以在redis控制台,用./redis-cli get myBean是看不到缓存内容的,只能得到nil的输出,不要误以为set没成功!通过代码是可以正常get到缓存值的。 

另外关于POJO对象的缓存,还有二个注意事项:

a) POJO类必须要有默认的无参构造函数,否则反序列化时会报错

b) ObjectRedisTemplate<T>中的T不能是接口,比如 DomainModelA继承自接口 IModelA,使用ObjectRedisTemplate时,要写成ObjectRedisTemplate<DomainModelA>而不是ObjectRedisTemplate<IModelA>,否则反序列化时也会出错


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值