redis -Spring与Jedis集群 Sentinel

news/2024/7/4 9:33:27

首先不得不服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配置

复制代码
 1     <bean id="redisSentinelConfiguration"
 2         class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
 3         <property name="master">
 4             <bean class="org.springframework.data.redis.connection.RedisNode">
 5                 <property name="name" value="mymaster"></property>
 6             </bean>
 7         </property>
 8         <property name="sentinels">
 9             <set>
10                 <bean class="org.springframework.data.redis.connection.RedisNode">
11                     <constructor-arg index="0" value="10.6.1**.**5" />
12                     <constructor-arg index="1" value="7031" />                    
13                 </bean>
14                 <bean class="org.springframework.data.redis.connection.RedisNode">
15                     <constructor-arg index="0" value="10.6.1**.**6" />
16                     <constructor-arg index="1" value="7031" />                
17                 </bean>
18                 <bean class="org.springframework.data.redis.connection.RedisNode">                    
19                     <constructor-arg index="0" value="10.6.1**.**1" />
20                     <constructor-arg index="1" value="7031" />                
21                 </bean>
22             </set>
23         </property>
24     </bean>
25 
26      <bean id="jedisConnFactory"
27         class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
28         <constructor-arg ref="redisSentinelConfiguration" />        
29     </bean>
30 
31     <bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
32         <property name="connectionFactory" ref="jedisConnFactory" />
33     </bean>
复制代码

提示:上面配置中的端口为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写入缓存.

 

三、单元测试

复制代码
 1     @Test
 2     public void testSpringRedis() {
 3         ConfigurableApplicationContext ctx = null;
 4         try {
 5             ctx = new ClassPathXmlApplicationContext("spring.xml");
 6 
 7             StringRedisTemplate stringRedisTemplate = ctx.getBean("stringRedisTemplate", StringRedisTemplate.class);
 8 
 9             // String读写
10             stringRedisTemplate.delete("myStr");
11             stringRedisTemplate.opsForValue().set("myStr", "http://yjmyzz.cnblogs.com/");
12             System.out.println(stringRedisTemplate.opsForValue().get("myStr"));
13             System.out.println("---------------");
14 
15             // List读写
16             stringRedisTemplate.delete("myList");
17             stringRedisTemplate.opsForList().rightPush("myList", "A");
18             stringRedisTemplate.opsForList().rightPush("myList", "B");
19             stringRedisTemplate.opsForList().leftPush("myList", "0");
20             List<String> listCache = stringRedisTemplate.opsForList().range(
21                     "myList", 0, -1);
22             for (String s : listCache) {
23                 System.out.println(s);
24             }
25             System.out.println("---------------");
26 
27             // Set读写
28             stringRedisTemplate.delete("mySet");
29             stringRedisTemplate.opsForSet().add("mySet", "A");
30             stringRedisTemplate.opsForSet().add("mySet", "B");
31             stringRedisTemplate.opsForSet().add("mySet", "C");
32             Set<String> setCache = stringRedisTemplate.opsForSet().members(
33                     "mySet");
34             for (String s : setCache) {
35                 System.out.println(s);
36             }
37             System.out.println("---------------");
38 
39             // Hash读写
40             stringRedisTemplate.delete("myHash");
41             stringRedisTemplate.opsForHash().put("myHash", "PEK", "北京");
42             stringRedisTemplate.opsForHash().put("myHash", "SHA", "上海虹桥");
43             stringRedisTemplate.opsForHash().put("myHash", "PVG", "浦东");
44             Map<Object, Object> hashCache = stringRedisTemplate.opsForHash()
45                     .entries("myHash");
46             for (Map.Entry<Object, Object> entry : hashCache.entrySet()) {
47                 System.out.println(entry.getKey() + " - " + entry.getValue());
48             }
49 
50             System.out.println("---------------");
51 
52         } finally {
53             if (ctx != null && ctx.isActive()) {
54                 ctx.close();
55             }
56         }
57 
58     }
复制代码

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

...

信息: 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可以参考以下代码

复制代码
 1     @Test
 2     public void testGetAllMasterAndSlaves() {
 3         ApplicationContext ctx = new FileSystemXmlApplicationContext("D:/spring-redis.xml");
 4         StringRedisTemplate template = ctx.getBean(StringRedisTemplate.class);
 5         RedisSentinelConnection conn = template.getConnectionFactory().getSentinelConnection();
 6         for (RedisServer m : conn.masters()) {
 7             System.out.println("master => " + m);//打印master信息
 8             Collection<RedisServer> slaves = conn.slaves(m);
 9             //打印该master下的所有slave信息
10             for (RedisServer s : slaves) {
11                 System.out.println("slaves of " + m + " => " + s);
12             }
13             System.out.println("--------------");
14         }
15         ((FileSystemXmlApplicationContext) ctx).close();
16     }
复制代码

输出类似下面的结果:

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>,否则反序列化时也会出错

 

http://www.cnblogs.com/yjmyzz/p/4113019.html


http://www.niftyadmin.cn/n/3297553.html

相关文章

轮播图会用到java的哪些功能,原生JS实现的轮播图功能详解

本文实例讲述了原生JS实现的轮播图功能。分享给大家供大家参考&#xff0c;具体如下&#xff1a;一、效果预览&#xff1a;由于只能上传2M以下的图片&#xff0c;这里只截取了自动切换的效果&#xff1a;二、编写语言HTML、CSS、原生JS三、编写思路(一)HTML部分1、.slide意为滑…

常用 ajax 框架比较--摘自网络

No1—Prototype http://www.prototypejs.org/特点&#xff1a;一个非常优雅的JS库&#xff0c;定义了JS的面向对象扩展&#xff0c;DOM操作API&#xff0c;事件等等&#xff0c;之上还有rico/script.aculo.us实现一些JS组件功能和效果(尚不够完善)&#xff0c;以prototype为核心…

kafka mysql 迁移,kafka迁移数据目录

问题先前存储kafka日志的磁盘空间太小&#xff0c;zabbix警报不断&#xff0c;于是加了磁盘&#xff0c;将日志存到新磁盘上。解决方案依次在每台机器上操作&#xff0c;保证有机器能响应producer和consumer的操作。加磁盘需要重启服务器。1. 拷贝日志服务器启动后&#xff0c;…

js时间格式化通用方法

/*** 时间工具类*//*** 获取现在的时间戳&#xff08;精确到s&#xff09;* 使用&#xff1a;new Date().nowTimestamp* type {number}*/ Date.prototype.nowTimestamp Date.parse(new Date()) / 1000;/*** 时间戳转换成Date* 使用&#xff1a;new Date().timestampToDate(149…

redis 3.0的集群部署

文章转载自&#xff1a;http://hot66hot.iteye.com/blog/2050676 转载请注明出处:http://hot66hot.iteye.com/admin/blogs/2050676 最近研究redis-cluster,正好搭建了一个环境,遇到了很多坑,系统的总结下,等到redis3 release出来后&#xff0c;换掉memCache 集群. 一:关于redis…

部分去重复php,找到重复小数的重复部分 – PHP

要说这并不像我想象的那么容易.但我得到了它的工作.我确信有一种更有效的方法可以做到这一点,希望其他人会改进这一点.特别是它被打印的部分.$number1 $number / $divisor;if(findRepeat( $number1 ) ! false){$result findRepeat($number1);$leadingNum strstr($number1, .…

深入理解ASP.NET MVC(4)

系列目录 DataTokens和Areas机制 到目前为止Route对象只剩下DataTokens属性没有涉及&#xff0c;事实上这个Areas机制的核心。 DataTokens实际上也是一个RouteValueDictionary&#xff0c;在用MapRoute方法构造在Route构造的时候&#xff0c;可以传一个namespaces字符串数组&am…

mysql 数据 信息,Mysql 获取最近数据信息

今天select * from 表名 where to_days(时间字段名) to_days(now());昨天SELECT * FROM 表名 WHERE TO_DAYS( NOW( ) ) - TO_DAYS( 时间字段名) < 1近7天SELECT * FROM 表名 where DATE_SUB(CURDATE(), INTERVAL 7 DAY) < date(时间字段名)近30天SELECT * FROM 表名 whe…