Redis 3.X版本引入了集羣的新特性,爲了保證所開發系統的高可用性項目組決定引用Redis的集羣特性。對於Redis數據訪問的支持,目前主要有二種方式:1、以直接調用jedis來實現;2、使用spring-data-redis,經過spring的封裝來調用。下面分別對這二種方式如何操做Redis進行說明。html
1、利用Jedis來實現java
經過Jedis操做Redis Cluster的模型能夠參考Redis官網,具體以下:node
Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>();git
//Jedis Cluster will attempt to discover cluster nodes automaticallygithub
jedisClusterNodes.add(new HostAndPort("10.96.5.183",9001));redis
jedisClusterNodes.add(new HostAndPort("10.96.5.183",9002));spring
jedisClusterNodes.add(new HostAndPort("10.96.5.183",9003));服務器
JedisCluster jc = new JedisCluster(jedisClusterNodes);mvc
jc.set("foo","bar");maven
jc.get("foo";
2、利用spring-data-redis來實現
目前spring-data-redis已發佈的主幹版本都不能很好的支持Redis Cluster的新特性。爲了解決此問題spring-data-redis開源項目組單獨拉了一個315分支,但截止到目前還沒有發佈。下面在分析spring-data-redis源碼的基礎上配置spring實現操做Redis Cluster.下面分別針對XML和注入的方式進行說明。
315分支gitHub下載路徑以下:https://github.com/spring-projects/spring-data-redis
315分支源碼下載路徑:http://maven.springframework.org/snapshot/org/springframework/data/spring-data-redis/1.7.0.DATAREDIS-315-SNAPSHOT/
(1)採用setClusterNodes屬性方式構造RedisClusterConfiguration
代碼目錄結構以下所示:
src
com.example.bean
com.example.repo
com.example.repo.impl
resources
A.在resources目錄下增長spring-config.xml配置,配置以下:
<!--經過構造方法注入RedisNode-->
<bean id="clusterRedisNodes1" class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg value="10.96.5.183" />
<constructor-arg value="9002" type="int" />
</bean>
....
<!--setter方式注入-->
<bean id="redisClusterConfiguration" class="org.springframework.data.redis.connection.RedisClusterConfiguration">
<property name="clusterNodes">
<set>
<ref bean="clusterRedisNodes1"/>
<ref bean="clusterRedisNodes2"/>
<ref bean="clusterRedisNodes3"/>
</set>
</property>
<!--紅色所示部分在從gitHub上獲取的jar包中無對應setter方法,所以須要修改其對應的源碼。
另外,若是不設置clusterTimeOut值,源碼中默認爲2S。當集羣服務器與客戶端不在同一服務器上時,容易報:Could not get a resource from the Cluster;
若是不設置maxRedirects值,源碼中默認爲5。通常當此值設置過大時,容易報:Too many Cluster redirections -->
<property name="clusterTimeOut" value="10000" />
<property name="maxRedirects" value="5" />
</bean>
<!--setter方式注入,對應的屬性需存在setterXXX方法-->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxToal" value="1000" />
<property name="maxIdle" value="1000" />
<property name="maxWaitMillis" value="1000" />
</bean>
<bean id="jedisConnFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:use-pool="true">
<constructor-arg ref="redisClusterConfiguration" />
<constructor-arg ref="jedisPoolConfig" />
</bean>
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" p:connection-factory-ref="jedisConnFactory" />
<!--setter方式注入PersonRepoImpl-->
<bean id="personRepo" class="com.example.repo.impl.PersonRepoImpl">
<property name="redisTemplate" ref="redisTemplate" />
</bean>
注:加載lua文件
<bean id ="XXX" class="org.springframework.data.redis.core.script.DefaultRedisScript">
<property name="location" value="./redis/XXX.lua" />
<property name="resultType" value="java.lang.Void" />
</bean>
在com.example.repo.impl下增長PersonRepoImpl,主要包括屬性private RedisTemplate<String,Bean> redisTemplate(該屬性存在setterXXX方法,對應property屬性);
利用redisTemplate.opsForHash().put()便可完成對Redis Cluster的操做。
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new ClassPathResource("resources/spring-config.xml").getPath());
Repo repo =(Repo)context.getBean("personRepo");
(2)採用RedisClusterConfiguration(PropertySource<?> propertySource)方式構造RedisClusterConfiguration
代碼目錄結構以下所示:
src
com.redis.cluster.support.config
MonitorConfig
resources
spring-config.xml
redis.properties
A.在resources目錄下增長spring-config.xml配置,配置以下:
<!--配置文件加載-->
<context:property-placeholder location="resources/redis.properties"/>
<context:property-placeholder location="resources/xxx.properties"/>
<bean class="com.redis.cluster.support.config.MonitorConfig" />
<!--對靜態資源文件的訪問-->
<mvc:default-servlet-handler/>
<mvc:annotation-driven />
<context:component-scan base-package="com.redis.cluster"/>
B.添加redis.properties文件
spring.redis.cluster.nodes=10.48.193.201:7389,10.48.193.201:7388
spring.redis.cluster.timeout=2000
spring.redis.cluster.max-redirects=8
C.編寫初始化JedisConnectionFactory鏈接工廠的java類
@Configuration
public class MonitorConfig {
@Value("${spring.redis.cluster.nodes}")
private String clusterNodes;
@Value("${spring.redis.cluster.timeout}")
private Long timeout;
@Value("${spring.redis.cluster.max-redirects}")
private int redirects;
@Bean
public RedisClusterConfiguration getClusterConfiguration() {
Map<String, Object> source = new HashMap<String, Object>();
source.put("spring.redis.cluster.nodes", clusterNodes);
source.put("spring.redis.cluster.timeout", timeout);
source.put("spring.redis.cluster.max-redirects", redirects);
return new RedisClusterConfiguration(new MapPropertySource("RedisClusterConfiguration", source));
}
@Bean
public JedisConnectionFactory getConnectionFactory() {
return new JedisConnectionFactory(getClusterConfiguration());
}
@Bean
public JedisClusterConnection getJedisClusterConnection() {
return (JedisClusterConnection) getConnectionFactory().getConnection();
}
@Bean
public RedisTemplate getRedisTemplate() {
RedisTemplate clusterTemplate = new RedisTemplate();
clusterTemplate.setConnectionFactory(getConnectionFactory());
clusterTemplate.setKeySerializer(new DefaultKeySerializer());
clusterTemplate.setDefaultSerializer(new GenericJackson2JsonRedisSerializer());
return clusterTemplate;
}
}
D.經過註解方式使用JedisClusterConnection和RedisTemplate
@Autowired
JedisClusterConnection clusterConnection;
@Autowired
RedisTemplate redisTemplate;
3、簡單集成Spring
本身編寫jedisCluster的工廠類JedisClusterFactory,而後經過Spring注入的方式獲取jedisCluster,實現客戶端使用Redis3.0版本的集羣特性。
請參考:http://my.oschina.net/FACEqiu/blog/512773?fromerr=I2SnVz8P
http://www.cnblogs.com/niceplay/p/4992614.html
使用時,直接經過註解或者XML注入便可,以下所示:
@Autowired
JedisCluster jedisCluster;
或者
<bean id="testRedis" class="com.test.TestRedis">
<property name="jedisCluster" ref="jedisClusterFactory" />
</bean>
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new ClassPathResource("resources/spring-config.xml").getPath());
TestRedis testRedis=(TestRedis)context.getBean("testRedis");
4、Redis Cluster調試中常見錯誤
(1)當客戶端與集羣服務器不在同一臺服務器上時,有以下錯誤Could not get a resource from the Cluster
通常當客戶端與集羣服務器在同一臺服務器上時,操做Redis Cluster正常; 當兩者不在同一臺服務器上時報如上錯誤,多是clusterTimeOut時間設置太小;
(2)操做Redis時報Too many cluster redirections
初始化JedisCluster時,設定JedisCluster的maxRedirections.
JedisCluster(Set<HostAndPort> jedisClusterNode, int timeout, int maxRedirections) ;
JedisCluster jc = new JedisCluster(jedisClusterNodes,5000,1000);
請參考:https://gitHub.com/xetorthio/jedis/issues/659
(3)Redis Cluster數據寫入慢
檢查在經過./redis-trib命令創建集羣時,若是是經過127.0.0.1的方式創建的集羣,那麼在往Redis Cluster中寫入數據時寫入速度比較慢。能夠經過配置真實的IP來規避此問題。