spring整合redis集羣當年作的一個小優化

這是我參與更文挑戰的第11天,活動詳情查看: 更文挑戰node

無心翻出多年前代碼發現當時真的是小年輕啊。對於redis集羣接入spring真的是搞了大半天。當時本身特地解決一個場景的bug 。就是redis集羣宕機以後自動從新捕獲最新集羣狀態。不過到如今本身再沒有使用過集羣了。因此當時的bug究竟是本身沒有配置好仍是的確存在。這個還須要筆者後續繼續驗證!!!redis

上一篇詳細的贅述了Redis的curd操做及集羣的搭建。下面咱們開始將他整合到咱們實際的項目中去。個人項目採用的是標準的ssm框架,ssm框架這裏不說,直接開始整合。spring

  • 首先在maven管理中將咱們的jar包引入
<!--1.7.2 開始支持Redis 集羣-->
<dependency>				            
	<groupId>org.springframework.data</groupId>	
	<artifactId>spring-data-redis</artifactId>
	<version>1.7.2.RELEASE</version>
</dependency>
<!-- Redis 緩存Jar -->
<dependency>
	<groupId>redis.clients</groupId>
	<artifactId>jedis</artifactId>
	<version>2.9.0</version>
</dependency>

<!--下面就是spring的maven座標了,這裏就不寫了,讀者本身引入-->
複製代碼
  • 在spring配置文件中咱們能夠進行配置Redis,可是爲了將Redis分離容易修改我將它卸載另一個xml文件中,只要在spring配置文件中引入這個Redis配置文件就好了。

這裏寫圖片描述

  • 下面全部的記錄都是在Redis這個配置文件進行操做的。

Redis鏈接池配置

  • 這裏只是將設置鏈接池的一些基本屬性,好比說最大鏈接數,鏈接前屬性判斷等
<bean id="redisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
		<property name="maxTotal" value="${redis.maxTotal}" />
		<property name="maxIdle" value="${redis.maxIdle}" />
		<property name="maxWaitMillis" value="${redis.maxWait}" />
		<property name="testOnBorrow" value="${redis.testOnBorrow}" />
	</bean>
複製代碼
  • maxIdle:控制一個pool最多有多少個狀態爲idle的jedis實例;緩存

  • 在borrow一個jedis實例時,是否提早進行alidate操做;若是爲true,則獲得的jedis實例均是可用的markdown

  • maxWaitMillis : 表示當borrow一個jedis實例時,最大的等待時間,若是超過等待時間,則直接拋出JedisConnectionException;框架

Redis集羣配置

這裏咱們就是將咱們上一篇開啓的Redis服務引入到項目中來。clusterNodes就是咱們一個一個的Redis服務。maven

<!-- Redis集羣配置 -->
	 <bean id="redisClusterConfig" class="org.springframework.data.redis.connection.RedisClusterConfiguration">
		<property name="maxRedirects" value="3"></property>
		<property name="clusterNodes">
		    <set>
		        <bean class="org.springframework.data.redis.connection.RedisNode">
		            <constructor-arg name="host" value="127.0.0.1"></constructor-arg>
		            <constructor-arg name="port" value="7000"></constructor-arg>
		        </bean>
		        
		        <bean class="org.springframework.data.redis.connection.RedisNode">
		            <constructor-arg name="host" value="127.0.0.1"></constructor-arg>
		            <constructor-arg name="port" value="7004"></constructor-arg>
		        </bean>
		        <bean class="org.springframework.data.redis.connection.RedisNode">
		            <constructor-arg name="host" value="127.0.0.1"></constructor-arg>
		            <constructor-arg name="port" value="7005"></constructor-arg>
		        </bean>
		    </set>
		</property>
 	</bean> 
複製代碼

Redis鏈接工廠

咱們將上面的Redis服務節點和鏈接池引入到工廠中,有工程去生產一個可用的jedis提供咱們進行緩存的CURD操做!!post

<!-- ReDis鏈接工廠 -->
	<bean id="redis4CacheConnectionFactory"
		class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
		<constructor-arg name="clusterConfig" ref="redisClusterConfig" />
		<property name="timeout" value="${redis.timeout}" />
		<property name="poolConfig" ref="redisPoolConfig" />
	</bean>
複製代碼

Redis模板

提供了jedis進行操做咱們就要放道模板裏面給咱們調用!。性能

<!-- 存儲序列化 -->
	<bean name="stringRedisSerializer"
		class="org.springframework.data.redis.serializer.StringRedisSerializer" />

	<!-- 集羣Resis使用模板 -->
	<bean id="clusterRedisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
		<property name="connectionFactory" ref="redis4CacheConnectionFactory" />
		<property name="keySerializer" ref="stringRedisSerializer" />
		<property name="hashKeySerializer" ref="stringRedisSerializer" />
		<property name="valueSerializer" ref="stringRedisSerializer" />
		<property name="hashValueSerializer" ref="stringRedisSerializer" />
	</bean>
複製代碼

項目調用

在配置文件中都已經將jedis配置好了,咱們只須要經過這個模板就能夠對Redis進行CURD操做了。下面是個簡單的列子spa

clusterRedisTemplate.execute(new RedisCallback<Long>() {
			public Long doInRedis(RedisConnection connection)
					throws DataAccessException {
				byte[] keyb = key.getBytes();
				byte[] valueb = toByteArray(value);
				// 判斷當前值是否已經存在
				if (connection.exists(keyb)) {
					// 刪除原數據
					connection.del(keyb);
				}
				connection.set(keyb, valueb);
				return 1L;
			}
		});
複製代碼

源碼探究竟

在RedisClusterConfiguration類中咱們傳入的Redis服務node,咱們設置的是property而後該類中就開始執行下面代碼 這裏寫圖片描述

而後咱們在工廠中傳入這些節點,

這裏寫圖片描述

這個工廠給我提供了一個afterproperties方法,意思就是在這些參數設置完成以後執行的一個方法。

這裏寫圖片描述

在這裏咱們能夠看見一個creatPool的方法,這個就是去鏈接池裏建立鏈接 這裏寫圖片描述

Bug解決

上面的部署 會出現一個問題,就是在項目中,每次初始化時會重鏈接池中選擇一個可用的Redis服務鏈接,當這個Redis服務宕機後咱們的項目還會繼續鏈接這個Redis服務,咱們只能重新啓動項目,項目纔會重新從鏈接池中選擇新的Redis服務。

  • 解決辦法 我在每次操做Redis時都去重構鏈接池,這樣就保證我每次都會去鏈接池找一個正真可用的Redis服務。
  • 解決就是將RedisNode注入到項目中,每次都執行咱們上次看到的creatPool方法
/** Redis模板注入 */
	@Resource
	private RedisClusterConfiguration redisClusterConfig;
	private JedisConnectionFactory redis4CacheConnectionFactory;
	@Resource
	private RedisTemplate<String, Object> clusterRedisTemplate;
	//重構鏈接池
	private void init(){
		redis4CacheConnectionFactory=new JedisConnectionFactory(redisClusterConfig);
		redis4CacheConnectionFactory.afterPropertiesSet();
		clusterRedisTemplate.setConnectionFactory(redis4CacheConnectionFactory);
	}
複製代碼

這樣又出現問題了,每次都初始化鏈接池,這在鏈接池上很費性能,暫時沒有解決辦法,可是我初步想經過redis sentinel 來檢測Redis集羣中的Redis服務。當Redis宕機後經過sentinel 提供的API來通知項目從新去構建鏈接池,從新鏈接新Redis服務

相關文章
相關標籤/搜索