javascript
Spring整合redis,通过sentinel进行主从切换。(何志雄)--转
原文地址:http://blog.csdn.net/tzszhzx/article/details/44590871
實現功能描述:
??????? 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依賴配置
<dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-redis</artifactId><version>1.4.1.RELEASE</version></dependency><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>2.6.2</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.3.2</version></dependency>2、redis.properties
# Redis settings #sentinel1的IP和端口 im.hs.server.redis.sentinel1.host=192.168.62.154 im.hs.server.redis.sentinel1.port=26379 #sentinel2的IP和端口 im.hs.server.redis.sentinel2.host=192.168.62.153 im.hs.server.redis.sentinel2.port=26379 #sentinel的鑒權密碼 im.hs.server.redis.sentinel.masterName=155Master im.hs.server.redis.sentinel.password=hezhixiong #最大閑置連接數 im.hs.server.redis.maxIdle=500 #最大連接數,超過此連接時操作redis會報錯 im.hs.server.redis.maxTotal=5000 im.hs.server.redis.maxWaitTime=1000 im.hs.server.redis.testOnBorrow=true #最小閑置連接數,spring啟動的時候自動建立該數目的連接供應用程序使用,不夠的時候會申請。 im.hs.server.redis.minIdle=3003、spring-redis.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!-- Spring自動將該包目錄下標記為@Service的所有類作為spring的Bean --><context:component-scan base-package="com.gaojiasoft.test.redis" /><context:property-placeholder location="classpath:conf/redis/redis.properties" /><bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"><property name="maxTotal" value="${im.hs.server.redis.maxTotal}" /><property name="minIdle" value="${im.hs.server.redis.minIdle}" /><property name="maxWaitMillis" value="${im.hs.server.redis.maxWaitTime}" /><property name="maxIdle" value="${im.hs.server.redis.maxIdle}" /><property name="testOnBorrow" value="${im.hs.server.redis.testOnBorrow}" /><property name="testOnReturn" value="true" /><property name="testWhileIdle" value="true" /></bean><bean id="sentinelConfiguration"class="org.springframework.data.redis.connection.RedisSentinelConfiguration"><property name="master"><bean class="org.springframework.data.redis.connection.RedisNode"><property name="name" value="${im.hs.server.redis.sentinel.masterName}"></property></bean></property><property name="sentinels"><set><bean class="org.springframework.data.redis.connection.RedisNode"><constructor-arg name="host"value="${im.hs.server.redis.sentinel1.host}"></constructor-arg><constructor-arg name="port"value="${im.hs.server.redis.sentinel1.port}"></constructor-arg></bean><bean class="org.springframework.data.redis.connection.RedisNode"><constructor-arg name="host"value="${im.hs.server.redis.sentinel2.host}"></constructor-arg><constructor-arg name="port"value="${im.hs.server.redis.sentinel2.port}"></constructor-arg></bean></set></property></bean><bean id="connectionFactory"class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:password="${im.hs.server.redis.sentinel.password}"><constructor-arg name="sentinelConfig" ref="sentinelConfiguration"></constructor-arg><constructor-arg name="poolConfig" ref="poolConfig"></constructor-arg></bean><bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate"><property name="connectionFactory" ref="connectionFactory" /></bean> </beans><strong> </strong>4、RedisServiceImpl.java
package com.gaojiasoft.test.redis;import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit;import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; @Service("redisService") public class RedisServiceImpl { private Logger logger = LoggerFactory.getLogger("RedisServiceImpl"); @Autowired RedisTemplate<?, ?> redisTemplate; // 線程池 private static final ThreadPoolExecutor executor = new ThreadPoolExecutor( 256, 256, 30L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new BasicThreadFactory.Builder().daemon(true) .namingPattern("redis-oper-%d").build(), new ThreadPoolExecutor.CallerRunsPolicy()); public void set(final String key, final String value) { redisTemplate.execute(new RedisCallback<Object>() { @Override public Object doInRedis(RedisConnection connection) throws DataAccessException { connection.set( redisTemplate.getStringSerializer().serialize(key), redisTemplate.getStringSerializer().serialize(value)); logger.debug("save key:" + key + ",value:" + value); return null; } }); } public String get(final String key) { return redisTemplate.execute(new RedisCallback<String>() { @Override public String doInRedis(RedisConnection connection) throws DataAccessException { byte[] byteKye = redisTemplate.getStringSerializer().serialize( key); if (connection.exists(byteKye)) { byte[] byteValue = connection.get(byteKye); String value = redisTemplate.getStringSerializer() .deserialize(byteValue); logger.debug("get key:" + key + ",value:" + value); return value; } logger.error("valus does not exist!,key:"+key); return null; } }); } public void delete(final String key) { redisTemplate.execute(new RedisCallback<Object>() { public Object doInRedis(RedisConnection connection) { connection.del(redisTemplate.getStringSerializer().serialize( key)); return null; } }); } /** * 線程池并發操作redis * * @param keyvalue */ public void mulitThreadSaveAndFind(final String keyvalue) { executor.execute(new Runnable() { @Override public void run() { try { set(keyvalue, keyvalue); get(keyvalue); } catch (Throwable th) { // 防御性容錯,避免高并發下的一些問題 logger.error("", th); } } }); } }5、RedisTest.java???(Junit測試用例)
package com.gaojiasoft.test.redis;import org.junit.Test; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;public class RedisTest {private static ConfigurableApplicationContext context; RedisServiceImpl service; @Test public void testSave() throws InterruptedException { context = new ClassPathXmlApplicationContext( "classpath:conf/redis/spring-redis.xml"); service = (RedisServiceImpl) context.getBean("redisService"); int i = 1; while (true) { Thread.sleep(1); try { service.mulitThreadSaveAndFind("" + i); } catch (Exception e) { e.printStackTrace(); } i++; } } }?
轉載于:https://www.cnblogs.com/davidwang456/articles/11133248.html
總結
以上是生活随笔為你收集整理的Spring整合redis,通过sentinel进行主从切换。(何志雄)--转的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何判断服务器之间的服务是否可用?pin
- 下一篇: Elasticsearch 的前世今生