1. 程式人生 > >Redis叢集與spring的整合

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服務