Redis叢集與spring的整合
上一篇詳細的贅述了Redis的curd操作及叢集的搭建。下面我們開始將他整合到我們實際的專案中去。我的專案採用的是標準的ssm框架,ssm框架這裡不說,直接開始整合。
- 首先在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例項均是可用的
- maxWaitMillis : 表示當borrow一個jedis例項時,最大的等待時間,如果超過等待時間,則直接丟擲JedisConnectionException;
Redis叢集配置
這裡我們就是將我們上一篇開啟的Redis服務引入到專案中來。clusterNodes就是我們一個一個的Redis服務。
<!-- 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操作!!
<!-- 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操作了。下面是個簡單的列子
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服務