目前spring-data-redis到底支不支持springdataredis集群群的

Redis教程,Redis集群搭建与Spring-data-redis的使用(介绍篇) —技术博客
Redis教程,Redis集群搭建与Spring-data-redis的使用(介绍篇)
&&& ,& & 集群搭建系列:
Redis教程,Redis 集群搭建(介绍篇)本教程是采用Redis-cluster集群,是&&&&3.0以后提供的一种集群解决方案,并且挺容易的完成&&&&的集群搭建,但是其实还是有比较多的坑,这里也会把我遇到的坑简单说一下,当你遇到的时候也能快速的解决。1.Redis-cluster集群结构图结构细节说明:所有的&&&&节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽。节点的&&&&是通过集群中超过半数的节点检测失效时才生效。客户端与&&&&节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。Redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node&-&slot&-&value。2.Redis-cluster 选举容错处理3.Redis-cluster集群状态:选举过程是集群中所有master参与,如果半数以上master节点与master节点通信超过(cluster-node-timeout),认为当前master节点挂掉。集群状态是[ cluster_state:fail ]表示整个集群不可用,当集群不可用的时候,所有请求都会返回(CLUSTERDOWN The cluster is down)如果集群任意master挂掉,且当前master没有slave。集群进入fail状态,也可以理解成进群的slot映射[0-16383]不完成时进入fail状态。如果进群超过半数以上master挂掉,无论是否有slave集群进入fail状态。
如果本文对你有帮助,那么请你赞助我,让我更有激情的写下去,帮助更多的人。
版权所属:
原文地址:
转载时必须以链接形式注明原始出处及本声明。
工具导航地图
JSON相关:
常用对照表:-
前&&&&&&&&&&端:-
转&&&&&&&&&&换:-
单位换算:-
生活工具:-
格式化、压缩:-
二&&维&&码:-
站长工具:-
月供计算:-
税费计算: -
还款工具:-
时间工具:
归属网站:
与我们合作:
点击加QQ群关于Spring Data redis几种对象序列化的比较 - Spring - Java - ITeye论坛
关于Spring Data redis几种对象序列化的比较
锁定老帖子
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
积分: 2310
来自: 厦门
发表时间:&&
最后修改:
相关知识库:
&&& 最近在整一个spring data redis,网上有一本《Spring Data》的电子书(我一个朋友正在翻译,应该今年会有中文版出来,人邮的),下载来看了一下,其中第8章讲到了Spring data对redis的支持。
&&& redis虽然提供了对list set hash等数据类型的支持,但是没有提供对POJO对象的支持,底层都是把对象序列化后再以字符串的方式存储的。因此,Spring data提供了若干个Serializer,主要包括:
JacksonJsonRedisSerializer
JdkSerializationRedisSerializer
OxmSerializer
&& 这里,我第一是想测试一下三者的使用,第二是想看看它们的使用效果。
下载源码&&
我直接在《Spring Data》书的源码基础上改,从这下载书的源码:
打开redis子项目,由于是以Maven组织的,所以不用关心包的问题。
添加一个测试的Entity
由于我们希望测试使用Redis保存POJO对象,因此我们在com.oreilly.springdata.redis包下创建一个User对象,如下所示:
package com.oreilly.springdata.
import javax.xml.bind.annotation.XmlAccessT
import javax.xml.bind.annotation.XmlAccessorT
import javax.xml.bind.annotation.XmlA
import javax.xml.bind.annotation.XmlRootE
import java.io.S
* @author : stamen
* @date: 13-7-16
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "user")
public class User implements Serializable {
@XmlAttribute
private String userN
@XmlAttribute
public String getUserName() {
return userN
public void setUserName(String userName) {
this.userName = userN
public int getAge() {
public void setAge(int age) {
this.age =
&& 由于后面,我们需要使用OXM及Jackson将进行对象序列,为了控制对象的序列化,因此打上了JSR 175注解。
更改ApplicationConfig
&& ApplicationConfig是Spring容器的配置类,要根据你的环境进行更改,我的更改为:
package com.oreilly.springdata.
import org.springframework.context.annotation.B
import org.springframework.context.annotation.C
import org.springframework.data.redis.connection.RedisConnectionF
import org.springframework.data.redis.connection.jedis.JedisConnectionF
import org.springframework.data.redis.core.RedisT
import org.springframework.data.redis.serializer.OxmS
import org.springframework.data.redis.serializer.RedisS
import org.springframework.data.redis.serializer.SerializationE
import org.springframework.oxm.jaxb.Jaxb2M
import javax.xml.bind.JAXBC
import javax.xml.bind.M
import java.util.HashM
import java.util.M
import java.util.concurrent.ConcurrentHashM
* @author Jon Brisbin
@Configuration
public abstract class ApplicationConfig {
public RedisConnectionFactory redisConnectionFactory() {
JedisConnectionFactory cf = new JedisConnectionFactory();
cf.setHostName("10.188.182.140");
cf.setPort(6379);
cf.setPassword("superman");
cf.afterPropertiesSet();
public RedisTemplate redisTemplate() {
RedisTemplate rt = new RedisTemplate();
rt.setConnectionFactory(redisConnectionFactory());
private static Map&Class, JAXBContext& jaxbContextHashMap = new ConcurrentHashMap&Class, JAXBContext&();
public OxmSerializer oxmSerializer() throws Throwable{
Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
Map&String,Object& properties = new HashMap&String, Object&();//创建映射,用于设置Marshaller属性
properties.put(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
//放置xml自动缩进属性
properties.put(Marshaller.JAXB_ENCODING,"utf-8");
//放置xml自动缩进属性
jaxb2Marshaller.setClassesToBeBound(User.class);//映射的xml类放入JAXB环境中
jaxb2Marshaller.setMarshallerProperties(properties);//设置Marshaller属性
new OxmSerializer(jaxb2Marshaller,jaxb2Marshaller);
public static enum StringSerializer implements RedisSerializer&String& {
public byte[] serialize(String s) throws SerializationException {
return (null != s ? s.getBytes() : new byte[0]);
public String deserialize(byte[] bytes) throws SerializationException {
if (bytes.length & 0) {
return new String(bytes);
public static enum LongSerializer implements RedisSerializer&Long& {
public byte[] serialize(Long aLong) throws SerializationException {
if (null != aLong) {
return aLong.toString().getBytes();
return new byte[0];
public Long deserialize(byte[] bytes) throws SerializationException {
if (bytes.length & 0) {
return Long.parseLong(new String(bytes));
public static enum IntSerializer implements RedisSerializer&Integer& {
public byte[] serialize(Integer i) throws SerializationException {
if (null != i) {
return i.toString().getBytes();
return new byte[0];
public Integer deserialize(byte[] bytes) throws SerializationException {
if (bytes.length & 0) {
return Integer.parseInt(new String(bytes));
&& 1)redisConnectionFactory()配置了如何连接Redsi服务器(如何安装Redis,参见:)
&& 2)oxmSerializer()是我新增的,用于定义一个基于Jaxb2Marshaller的OxmSerializer Bean(后面将会用到)
编写测试用例
&&& 打开KeyValueSerializersTest,我们几个额外的测试用例都将写在该测试类中:
使用JdkSerializationRedisSerializer序列化
public void testJdkSerialiable() {
RedisTemplate&String, Serializable& redis = new RedisTemplate&String, Serializable&();
redis.setConnectionFactory(connectionFactory);
redis.setKeySerializer(ApplicationConfig.StringSerializer.INSTANCE);
redis.setValueSerializer(new JdkSerializationRedisSerializer());
redis.afterPropertiesSet();
ValueOperations&String, Serializable& ops = redis.opsForValue();
User user1 = new User();
user1.setUserName("user1");
user1.setAge(20);
String key1 = "users/user1";
User user11 =
long begin = System.currentTimeMillis();
for (int i = 0; i & 100; i++) {
ops.set(key1,user1);
user11 = (User)ops.get(key1);
long time = System.currentTimeMillis() -
System.out.println("jdk time:"+time);
assertThat(user11.getUserName(),is("user1"));
&& JdkSerializationRedisSerializer支持对所有实现了Serializable的类进行序列化。运行该测试用例,我们通过redis-cli 通过“users/user1”键可以查看到对应的值,内容如下:
引用
redis 127.0.0.1:6379& get users/user1
"\xac\xed\x00\x05sr\x00!com.oreilly.springdata.redis.User\xb1\x1c \n\xcd\xed%\xd8\x02\x00\x02I\x00\x03ageL\x00\buserNamet\x00\x12Ljava/lang/Sxp\x00\x00\x00\x14t\x00\x05user1"
通过strlen查看对应的字符长度:
引用
redis 127.0.0.1:6379& strlen users/user1
(integer) 104
上面的代码共进行了100次的存储和获取,其所花时间如下(毫秒):
引用jdk time:266
使用JacksonJsonRedisSerializer序列化
public void testJacksonSerialiable() {
RedisTemplate&String, Object& redis = new RedisTemplate&String, Object&();
redis.setConnectionFactory(connectionFactory);
redis.setKeySerializer(ApplicationConfig.StringSerializer.INSTANCE);
redis.setValueSerializer(new JacksonJsonRedisSerializer&User&(User.class));
redis.afterPropertiesSet();
ValueOperations&String, Object& ops = redis.opsForValue();
User user1 = new User();
user1.setUserName("user1");
user1.setAge(20);
User user11 =
String key1 = "json/user1";
long begin = System.currentTimeMillis();
for (int i = 0; i & 100; i++) {
ops.set(key1,user1);
user11 = (User)ops.get(key1);
long time = System.currentTimeMillis() -
System.out.println("json time:"+time);
assertThat(user11.getUserName(),is("user1"));
&&& 运行后,查看redis的内容及内容长度:
引用
redis 127.0.0.1:6379& get json/user1
"{\"userName\":\"user1\",\"age\":20}"
redis 127.0.0.1:6379& strlen json/user1
(integer) 29
&&& 执行花费时间为:
引用
&&& json time:224
使用OxmSerialiable序列化
public void testOxmSerialiable() throws Throwable{
RedisTemplate&String, Object& redis = new RedisTemplate&String, Object&();
redis.setConnectionFactory(connectionFactory);
redis.setKeySerializer(ApplicationConfig.StringSerializer.INSTANCE);
redis.setValueSerializer(oxmSerializer);
redis.afterPropertiesSet();
ValueOperations&String, Object& ops = redis.opsForValue();
User user1 = new User();
user1.setUserName("user1");
user1.setAge(20);
User user11 =
String key1 = "oxm/user1";
long begin = System.currentTimeMillis();
for (int i = 0; i & 100; i++) {
ops.set(key1,user1);
user11 = (User)ops.get(key1);
long time = System.currentTimeMillis() -
System.out.println("oxm time:"+time);
assertThat(user11.getUserName(),is("user1"));
&&& 运行后,查看redis的内容及内容长度:
引用
redis 127.0.0.1:6379& get oxm/user1
"&?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?&\n&user age=\"20\" userName=\"user1\"/&\n"
redis 127.0.0.1:6379& strlen oxm/user1
(integer) 90
&&& 执行花费时间为:
引用
&&& oxm time:335
&&& 从执行时间上来看,JdkSerializationRedisSerializer是最高效的(毕竟是JDK原生的),但是是序列化的结果字符串是最长的。JSON由于其数据格式的紧凑性,序列化的长度是最小的,时间比前者要多一些。而OxmSerialiabler在时间上看是最长的(当时和使用具体的Marshaller有关)。所以个人的选择是倾向使用JacksonJsonRedisSerializer作为POJO的序列器。
下载次数: 255
等级: 初级会员
来自: 武汉
发表时间:&&
LZ可以试下/xetorthio/johm 还有试过复杂POJO对象么?
请登录后投票
积分: 2310
来自: 厦门
发表时间:&&
char1st 写道LZ可以试下/xetorthio/johm
还有试过复杂POJO对象么?
这个是很快,但是好像不是标准的东东吧。现在一般倾向于用JSR 175的Annotation来做序列化。
请登录后投票
等级: 初级会员
来自: 厦门--&北京
发表时间:&&
stamen 写道char1st 写道LZ可以试下/xetorthio/johm
还有试过复杂POJO对象么?
这个是很快,但是好像不是标准的东东吧。现在一般倾向于用JSR 175的Annotation来做序列化。
用hash存储的话,有一些好处的,比如某个字段的更新,以及原子性的支持
请登录后投票
文章: 1516
积分: 2448
来自: 上海
发表时间:&&
我记得fastjson的作者也有对象序列化的实现,可以试试那个。应该会有比较好的表现吧。
请登录后投票
跳转论坛:移动开发技术
Web前端技术
Java企业应用
编程语言技术Spring Boot中的缓存支持(二)使用Redis做集中式缓存 - 简书
Spring Boot中的缓存支持(二)使用Redis做集中式缓存
上一篇介绍了在Spring Boot中如何引入缓存、缓存注解的使用、以及EhCache的整合。
虽然EhCache已经能够适用很多应用场景,但是由于EhCache是进程内的缓存框架,在集群模式下时,各应用服务器之间的缓存都是独立的,因此在不同服务器的进程间会存在缓存不一致的情况。即使EhCache提供了集群环境下的缓存同步策略,但是同步依然需要一定的时间,短暂的缓存不一致依然存在。
在一些要求高一致性(任何数据变化都能及时的被查询到)的系统和应用中,就不能再使用EhCache来解决了,这个时候使用集中式缓存是个不错的选择,因此本文将介绍如何在Spring Boot的缓存支持中使用Redis进行数据缓存。
下面以上一篇的例子作为基础进行改造,将缓存内容迁移到redis中。
可以下载案例,进行下面改造步骤。
先来回顾一下在此案例中,我们做了什么内容:
引入了spring-data-jpa和EhCache
定义了User实体,包含id、name、age字段
使用spring-data-jpa实现了对User对象的数据访问接口UserRepository
使用Cache相关注解配置了缓存
单元测试,通过连续的查询和更新数据后的查询来验证缓存是否生效
删除EhCache的配置文件src/main/resources/ehcache.xml
pom.xml中删除EhCache的依赖,增加redis的依赖:
&dependency&
&groupId&org.springframework.boot&/groupId&
&artifactId&spring-boot-starter-redis&/artifactId&
&/dependency&
application.properties中增加redis配置,以本地运行为例,比如:
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.pool.max-idle=8
spring.redis.pool.min-idle=0
spring.redis.pool.max-active=8
spring.redis.pool.max-wait=-1
我们需要做的配置到这里就已经完成了,Spring Boot会在侦测到存在Redis的依赖并且Redis的配置是可用的情况下,使用RedisCacheManager初始化CacheManager。
为此,我们可以单步运行我们的单元测试,可以观察到此时CacheManager的实例是org.springframework.data.redis.cache.RedisCacheManager,并获得下面的执行结果:
Hibernate: insert into user (age, name) values (?, ?)
Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.name as name3_0_ from user user0_ where user0_.name=?
第一次查询:10
第二次查询:10
Hibernate: select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.name as name3_0_0_ from user user0_ where user0_.id=?
Hibernate: update user set age=?, name=? where id=?
第三次查询:10
可以观察到,在第一次查询的时候,执行了select语句;第二次查询没有执行select语句,说明是从缓存中获得了结果;而第三次查询,我们获得了一个错误的结果,根据我们的测试逻辑,在查询之前我们已经将age更新为20,但是我们从缓存中获取到的age还是为10。
为什么同样的逻辑在EhCache中没有问题,但是到Redis中会出现这个问题呢?
在EhCache缓存时没有问题,主要是由于EhCache是进程内的缓存框架,第一次通过select查询出的结果被加入到EhCache缓存中,第二次查询从EhCache取出的对象与第一次查询对象实际上是同一个对象(可以在使用Chapter4-4-1工程中,观察u1==u2来看看是否是同一个对象),因此我们在更新age的时候,实际已经更新了EhCache中的缓存对象。
而Redis的缓存独立存在于我们的Spring应用之外,我们对数据库中数据做了更新操作之后,没有通知Redis去更新相应的内容,因此我们取到了缓存中未修改的数据,导致了数据库与缓存中数据的不一致。
因此我们在使用缓存的时候,要注意缓存的生命周期,利用好上一篇上提到的几个注解来做好缓存的更新、删除
进一步修改
针对上面的问题,我们只需要在更新age的时候,通过@CachePut来让数据更新操作同步到缓存中,就像下面这样:
@CacheConfig(cacheNames = "users")
public interface UserRepository extends JpaRepository&User, Long& {
@Cacheable(key = "#p0")
User findByName(String name);
@CachePut(key = "#p0.name")
User save(User user);
在redis-cli中flushdb,清空一下之前的缓存内容,再执行单元测试,可以获得下面的结果:
Hibernate: insert into user (age, name) values (?, ?)
第一次查询:10
第二次查询:10
Hibernate: select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.name as name3_0_0_ from user user0_ where user0_.id=?
Hibernate: update user set age=?, name=? where id=?
第三次查询:20
可以看到,我们的第三次查询获得了正确的结果!同时,我们的第一次查询也不是通过select查询获得的,因为在初始化数据的时候,调用save方法时,就已经将这条数据加入了redis缓存中,因此后续的查询就直接从redis中获取了。
本文内容到此为止,主要介绍了为什么要使用Redis做缓存,以及如何在Spring Boot中使用Redis做缓存,并且通过一个小问题来帮助大家理解缓存机制,在使用过程中,一定要注意缓存生命周期的控制,防止数据不一致的情况出现。
完整示例:
会一些前端,懂一些后端,做过一些管理,弄过一些运维,搞过一些推广,我是一枚爱折腾的团队万金油…...

我要回帖

更多关于 springmvc redis集群 的文章

 

随机推荐