Spring-data-redis操作redis cluster


     Redis 3.X版本引入了集群的新特性,為了保證所開發系統的高可用性項目組決定引用Redis的集群特性。對於Redis數據訪問的支持,目前主要有二種方式:一、以直接調用jedis來實現;二、使用spring-data-redis,通過spring的封裝來調用。下面分別對這二種方式如何操作Redis進行說明。

一、利用Jedis來實現

      通過Jedis操作Redis Cluster的模型可以參考Redis官網,具體如下:

        Set<HostAndPort>  jedisClusterNodes = new HashSet<HostAndPort>();

          //Jedis Cluster will attempt to discover cluster nodes automatically

         jedisClusterNodes.add(new HostAndPort("10.96.5.183",9001));

         jedisClusterNodes.add(new HostAndPort("10.96.5.183",9002));

         jedisClusterNodes.add(new HostAndPort("10.96.5.183",9003));

        JedisCluster jc = new JedisCluster(jedisClusterNodes);

        jc.set("foo","bar");

        jc.get("foo";

二、利用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.RedisTemplatep: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;

三、簡單集成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");

四、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來規避此問題。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM