Spring整合redis,通过sentinel进行主从切换

来源:互联网 发布:js array filter方法 编辑:程序博客网 时间:2024/04/25 10:01

实现功能描述:

        redis服务器进行Master-slaver-slaver-....主从配置,通过2台sentinel进行failOver故障转移,自动切换,采用该代码完全可以直接用于实际生产环境。

       

       题外话:

         一般来说这样的部署足以支持数以百万级的用户,但如果数量实在是太高,此时redis的Master-Slaver主从不一定能够满足,因此进行redis的分片。

        本文不讲解redis的分片,但如果你使用了,需要注意的按照另一篇文章的介绍:Sentinel&Jedis看上去是个完美的解决方案,这句话只说对了一半,

         在无分片的情况是这样,但我们的应用使用了数据分片-sharing,数据被平均分布到4个不同的实例上,每个实例以主从结构部署,Jedis没有提供

         基于Sentinel的ShardedJedisPool,也就是说在4个分片中,如果其中一个分片发生主从切换,应用所使用的ShardedJedisPool无法获得通知,所有

         对那个分片的操作将会失败。文章中提出了解决方案,请参考《基于Redis Sentinel的Redis集群(主从&Sharding)高可用方案》

        

 

 

        该代码模拟多线程向redis中set/get。

 

1、maven依赖配置

[html] view plain copy
  1. <dependency>  
  2.     <groupId>org.springframework.data</groupId>  
  3.         <artifactId>spring-data-redis</artifactId>  
  4.         <version>1.4.1.RELEASE</version>  
  5.     </dependency>  
  6.     <dependency>  
  7.         <groupId>redis.clients</groupId>  
  8.         <artifactId>jedis</artifactId>  
  9.         <version>2.6.2</version>  
  10.     </dependency>  
  11.     <dependency>  
  12.         <groupId>org.apache.commons</groupId>  
  13.         <artifactId>commons-lang3</artifactId>  
  14.         <version>3.3.2</version>  
  15. </dependency>  


 

2、redis.properties

[plain] view plain copy
  1. # Redis settings  
  2. #sentinel1的IP和端口  
  3. im.hs.server.redis.sentinel1.host=192.168.62.154  
  4. im.hs.server.redis.sentinel1.port=26379  
  5. #sentinel2的IP和端口  
  6. im.hs.server.redis.sentinel2.host=192.168.62.153  
  7. im.hs.server.redis.sentinel2.port=26379  
  8. #sentinel的鉴权密码  
  9. im.hs.server.redis.sentinel.masterName=155Master  
  10. im.hs.server.redis.sentinel.password=hezhixiong  
  11. #最大闲置连接数  
  12. im.hs.server.redis.maxIdle=500  
  13. #最大连接数,超过此连接时操作redis会报错  
  14. im.hs.server.redis.maxTotal=5000  
  15. im.hs.server.redis.maxWaitTime=1000  
  16. im.hs.server.redis.testOnBorrow=true  
  17. #最小闲置连接数,spring启动的时候自动建立该数目的连接供应用程序使用,不够的时候会申请。  
  18. im.hs.server.redis.minIdle=300  


3、spring-redis.xml

[html] view plain copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"  
  4.     xmlns:context="http://www.springframework.org/schema/context"  
  5.     xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"  
  6.     xmlns:aop="http://www.springframework.org/schema/aop"  
  7.     xsi:schemaLocation="  
  8.             http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
  9.             http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">  
  10.   
  11.     <!-- Spring自动将该包目录下标记为@Service的所有类作为spring的Bean -->  
  12.     <context:component-scan base-package="com.gaojiasoft.test.redis" />  
  13.   
  14.     <context:property-placeholder location="classpath:conf/redis/redis.properties" />  
  15.   
  16.     <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">  
  17.         <property name="maxTotal" value="${im.hs.server.redis.maxTotal}" />  
  18.         <property name="minIdle" value="${im.hs.server.redis.minIdle}" />  
  19.         <property name="maxWaitMillis" value="${im.hs.server.redis.maxWaitTime}" />  
  20.         <property name="maxIdle" value="${im.hs.server.redis.maxIdle}" />  
  21.         <property name="testOnBorrow" value="${im.hs.server.redis.testOnBorrow}" />  
  22.         <property name="testOnReturn" value="true" />  
  23.         <property name="testWhileIdle" value="true" />  
  24.     </bean>  
  25.   
  26.     <bean id="sentinelConfiguration"  
  27.         class="org.springframework.data.redis.connection.RedisSentinelConfiguration">  
  28.         <property name="master">  
  29.             <bean class="org.springframework.data.redis.connection.RedisNode">  
  30.                 <property name="name" value="${im.hs.server.redis.sentinel.masterName}"></property>  
  31.             </bean>  
  32.         </property>  
  33.         <property name="sentinels">  
  34.             <set>  
  35.                 <bean class="org.springframework.data.redis.connection.RedisNode">  
  36.                     <constructor-arg name="host"  
  37.                         value="${im.hs.server.redis.sentinel1.host}"></constructor-arg>  
  38.                     <constructor-arg name="port"  
  39.                         value="${im.hs.server.redis.sentinel1.port}"></constructor-arg>  
  40.                 </bean>  
  41.                 <bean class="org.springframework.data.redis.connection.RedisNode">  
  42.                     <constructor-arg name="host"  
  43.                         value="${im.hs.server.redis.sentinel2.host}"></constructor-arg>  
  44.                     <constructor-arg name="port"  
  45.                         value="${im.hs.server.redis.sentinel2.port}"></constructor-arg>  
  46.                 </bean>  
  47.             </set>  
  48.         </property>  
  49.     </bean>  
  50.   
  51.     <bean id="connectionFactory"  
  52.         class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:password="${im.hs.server.redis.sentinel.password}">  
  53.         <constructor-arg name="sentinelConfig" ref="sentinelConfiguration"></constructor-arg>  
  54.         <constructor-arg name="poolConfig" ref="poolConfig"></constructor-arg>  
  55.     </bean>  
  56.   
  57.     <bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">  
  58.         <property name="connectionFactory" ref="connectionFactory" />  
  59.     </bean>  
  60. </beans><strong>  
  61. </strong>  

 

4、RedisServiceImpl.Java

[java] view plain copy
  1. package com.gaojiasoft.test.redis;  
  2.   
  3. import java.util.concurrent.LinkedBlockingQueue;  
  4. import java.util.concurrent.ThreadPoolExecutor;  
  5. import java.util.concurrent.TimeUnit;  
  6.   
  7. import org.apache.commons.lang3.concurrent.BasicThreadFactory;  
  8. import org.slf4j.Logger;  
  9. import org.slf4j.LoggerFactory;  
  10. import org.springframework.beans.factory.annotation.Autowired;  
  11. import org.springframework.dao.DataAccessException;  
  12. import org.springframework.data.redis.connection.RedisConnection;  
  13. import org.springframework.data.redis.core.RedisCallback;  
  14. import org.springframework.data.redis.core.RedisTemplate;  
  15. import org.springframework.stereotype.Service;  
  16.   
  17. @Service("redisService")  
  18. public class RedisServiceImpl {  
  19.   
  20.     private Logger logger = LoggerFactory.getLogger("RedisServiceImpl");  
  21.   
  22.     @Autowired  
  23.     RedisTemplate<?, ?> redisTemplate;  
  24.   
  25.     // 线程池  
  26.     private static final ThreadPoolExecutor executor = new ThreadPoolExecutor(  
  27.             256256, 30L, TimeUnit.SECONDS,  
  28.             new LinkedBlockingQueue<Runnable>(),  
  29.             new BasicThreadFactory.Builder().daemon(true)  
  30.                     .namingPattern("redis-oper-%d").build(),  
  31.             new ThreadPoolExecutor.CallerRunsPolicy());  
  32.   
  33.     public void set(final String key, final String value) {  
  34.         redisTemplate.execute(new RedisCallback<Object>() {  
  35.             @Override  
  36.             public Object doInRedis(RedisConnection connection)  
  37.                     throws DataAccessException {  
  38.                 connection.set(  
  39.                         redisTemplate.getStringSerializer().serialize(key),  
  40.                         redisTemplate.getStringSerializer().serialize(value));  
  41.                 logger.debug("save key:" + key + ",value:" + value);  
  42.                 return null;  
  43.             }  
  44.         });  
  45.     }  
  46.   
  47.     public String get(final String key) {  
  48.         return redisTemplate.execute(new RedisCallback<String>() {  
  49.             @Override  
  50.             public String doInRedis(RedisConnection connection)  
  51.                     throws DataAccessException {  
  52.                 byte[] byteKye = redisTemplate.getStringSerializer().serialize(  
  53.                         key);  
  54.                 if (connection.exists(byteKye)) {  
  55.                     byte[] byteValue = connection.get(byteKye);  
  56.                     String value = redisTemplate.getStringSerializer()  
  57.                             .deserialize(byteValue);  
  58.                     logger.debug("get key:" + key + ",value:" + value);  
  59.                     return value;  
  60.                 }  
  61.                 logger.error("valus does not exist!,key:"+key);  
  62.                 return null;  
  63.             }  
  64.         });  
  65.     }  
  66.   
  67.     public void delete(final String key) {  
  68.         redisTemplate.execute(new RedisCallback<Object>() {  
  69.             public Object doInRedis(RedisConnection connection) {  
  70.                 connection.del(redisTemplate.getStringSerializer().serialize(  
  71.                         key));  
  72.                 return null;  
  73.             }  
  74.         });  
  75.     }  
  76.   
  77.     /** 
  78.      * 线程池并发操作redis 
  79.      *  
  80.      * @param keyvalue 
  81.      */  
  82.     public void mulitThreadSaveAndFind(final String keyvalue) {  
  83.         executor.execute(new Runnable() {  
  84.             @Override  
  85.             public void run() {  
  86.                 try {  
  87.                     set(keyvalue, keyvalue);  
  88.                     get(keyvalue);  
  89.                 } catch (Throwable th) {  
  90.                     // 防御性容错,避免高并发下的一些问题  
  91.                     logger.error("", th);  
  92.                 }  
  93.             }  
  94.         });  
  95.     }  
  96. }  


5、RedisTest.java   (Junit测试用例)

[java] view plain copy
  1. package com.gaojiasoft.test.redis;  
  2.   
  3. import org.junit.Test;  
  4. import org.springframework.context.ConfigurableApplicationContext;  
  5. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  6.   
  7. public class RedisTest {  
  8.   
  9.     private static ConfigurableApplicationContext context;  
  10.   
  11.     RedisServiceImpl service;  
  12.   
  13.     @Test  
  14.     public void testSave() throws InterruptedException {  
  15.         context = new ClassPathXmlApplicationContext(  
  16.                 "classpath:conf/redis/spring-redis.xml");  
  17.         service = (RedisServiceImpl) context.getBean("redisService");  
  18.   
  19.         int i = 1;  
  20.         while (true) {  
  21.             Thread.sleep(1);  
  22.             try {  
  23.                 service.mulitThreadSaveAndFind("" + i);  
  24.             } catch (Exception e) {  
  25.                 e.printStackTrace();  
  26.             }  
  27.             i++;  
  28.         }  
  29.     }  
  30. }  
0 0
原创粉丝点击