spring整合redis集羣的相關配置(senlient模式)

研究Redis也有一段時間了,在前面的Redis系列文章中,介紹了Redis的安裝,集羣配置,及節點的增加和刪除,但是並未實際的使用到項目中,趁這週末時間,參照項目中實際的使用場景,做了一個Redis集羣Spring整合的案例,在介紹案例之前,先簡單介紹下Redis集羣的方式有哪些 
1、單機版 不解釋 
2、Sentinel 哨兵模式 
3、Redis Cluster Redis官方集羣方案 
4、Redis Sharding集羣

正確的說,哨兵模式是一主多從的結構,並不屬於真正的集羣,真正的集羣應該是多主多從的結構,需要有多臺不同物理地址的主機,無賴家裏只有一臺PC,只能使用Sentinel模式來做集羣。先來看下Sentinel模式的集羣架構圖 
這裏寫圖片描述
首先需要有一臺監控服務器,也就是Sentinel,一臺主服務器Master,多臺從服務器Slave,具體的配置可以參考另一篇博文《Redis序列之Sentinel》,假設Sentinel,Master,Slave都已經配置好了,對應地址分別爲: 
Sentinel 127.0.0.1:26379,127.0.0.1:26479 
Master 127.0.0.1:10003 
Slave 127.0.0.1:10001,127.0.0.1:10002

接下來開始Java端的配置準備工作 
1、在Maven的pom.xml文件中,增加redis的引用

<!--如果用1.7.5的版本,啓動會有問題因此使用1.5.2的版本-->
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-redis</artifactId>
    <version>1.5.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.0</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

2、增加redis.properties文件,文件中只需要指定sentinel即可(原來一直誤認爲是配置master和slave),文件內容如下

redis.sentinel.host1=127.0.0.1
redis.sentinel.port1=26379

redis.sentinel.host2=127.0.0.1
redis.sentinel.port2=26479

redis.pool.maxTotal=1024 
redis.pool.maxIdle=200 
redis.pool.maxWaitMillis=1000 
redis.pool.testOnBorrow=true 

redis.pool.timeBetweenEvictionRunsMillis=30000 
redis.pool.minEvictableIdleTimeMillis=30000 
redis.pool.softMinEvictableIdleTimeMillis=10000 
redis.pool.numTestsPerEvictionRun=1024 

#1000*60*60*1
redis.pool.expire=3600000
redis.pool.unlock=false 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

3、在Spring的applicationContext.xml文件中,增加Redis的配置

<!-- redis屬性文件 -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
       <list>
          <value>classpath:config/redis.properties</value>
       </list>
    </property>
</bean>

<!-- 啓動緩存註解功能,否則緩解不會生效 -->
<cache:annotation-driven cache-manager="cacheManager"/>

<!-- redis屬性配置 -->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
       <property name="maxTotal" value="${redis.pool.maxTotal}" />
       <property name="maxIdle" value="${redis.pool.maxIdle}" />
       <property name="numTestsPerEvictionRun" value="${redis.pool.numTestsPerEvictionRun}" />
       <property name="timeBetweenEvictionRunsMillis" value="${redis.pool.timeBetweenEvictionRunsMillis}" />
       <property name="minEvictableIdleTimeMillis" value="${redis.pool.minEvictableIdleTimeMillis}" />
       <property name="softMinEvictableIdleTimeMillis" value="${redis.pool.softMinEvictableIdleTimeMillis}" />
       <property name="maxWaitMillis" value="${redis.pool.maxWaitMillis}" />
       <property name="testOnBorrow" value="${redis.pool.testOnBorrow}" />
</bean>

 <!-- redis集羣配置 哨兵模式 -->
<bean id="sentinelConfiguration" class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
    <property name="master">
        <bean class="org.springframework.data.redis.connection.RedisNode">
            <!--這個值要和Sentinel中指定的master的值一致,不然啓動時找不到Sentinel會報錯的-->
            <property name="name" value="mymaster"></property>
        </bean>
    </property>
    <!--記住了,這裏是指定Sentinel的IP和端口,不是Master和Slave的-->
    <property name="sentinels">
        <set>
            <bean class="org.springframework.data.redis.connection.RedisNode">
                <constructor-arg name="host" value="${redis.sentinel.host1}"></constructor-arg>
                <constructor-arg name="port" value="${redis.sentinel.port1}"></constructor-arg>
            </bean>
            <bean class="org.springframework.data.redis.connection.RedisNode">
                <constructor-arg name="host" value="${redis.sentinel.host2}"></constructor-arg>
                <constructor-arg name="port" value="${redis.sentinel.port2}"></constructor-arg>
            </bean>
        </set>
    </property>
</bean>
<bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.RedisConnectionFactory">
    <constructor-arg name="sentinelConfig" ref="sentinelConfiguration"></constructor-arg>
    <constructor-arg name="poolConfig" ref="jedisPoolConfig"></constructor-arg>
</bean>
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
    <property name="connectionFactory" ref="redisConnectionFactory"></property>
</bean>
<!-- 緩存管理器 -->
<bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager">
    <constructor-arg ref="redisTemplate" />
</bean>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

特別說明: 
1、Sentinel的集羣模型,在Java端配置時,只需要指定有哪些Sentinel就可以了,不需要指定Master和Slave,之前不清楚,導致啓動一直報找不到可用的Sentinel 
2、在Spring配置文件中一定要增加<cache:annotation-driven cache-manager="cacheManager"/>註解聲明,否則緩存不會生效,之前緩存一直不生效的原因就是這個 
3、<cache:annotation-driven/>的cache-manager屬性默認值是cacheManager,默認情況下可以不指定,如果我們的定義的CacheManager名稱不是cacheManager,就需要顯示指定; 
<cache:annotation-driven/> 的另一個屬性是model,可選值是proxy和aspectj,默認是proxy,當model=proxy時,只有當緩存方法在聲名的類外部被調用時,spring cache纔會生效,換句話說就是如果在同一個類中一個方法調用當前類的緩存方法,緩存不生效,而model=aspectj時就不會有這個問題;另外model=proxy時,@Cacheable等註解加在public方法上,緩存纔會生效,加在private上是不會生效的,而model=aspectj時也不會有這個問題 
<cache:annotation-driven/> 還可以指定一個proxy-target-class屬性,表示是否要代理class,默認爲false。@Cacheable、@cacheEvict等也可以標註在接口上,這對於基於接口的代理來說是沒有什麼問題的,但要注意的是當設置proxy-target-class爲true或者mode爲aspectj時,是直接基於class進行操作的,定義在接口上的@Cacheable等Cache註解不會被識別到,對應的Spring Cache也不會起作用

以上準備工作完成後,就可以在Java代碼中使用Redis了,很多人是以硬編碼的方式在代碼中使用緩存,這種對業務代碼的侵入性是很強的,不方便後期的維護和擴展,這裏使用註解方式,只需要在類或方法名上增加註解就可以了

@Override
@Cacheable(value="user")
public UserVO selectUserById(String userId) throws Exception {
    return userDao.selectUserById(userId);
}
  • 1
  • 2
  • 3
  • 4
  • 5

現在把Tomcat服務啓動起來,發現Sentinel已經加載進來了,顯示127.0.0.1:10003是Master

一月 02, 2017 11:53:09 下午 redis.clients.jedis.JedisSentinelPool initSentinels
信息: Trying to find master from available Sentinels...
一月 02, 2017 11:53:14 下午 redis.clients.jedis.JedisSentinelPool initSentinels
信息: Redis master running at 127.0.0.1:10003, starting Sentinel listeners...
一月 02, 2017 11:53:14 下午 redis.clients.jedis.JedisSentinelPool initPool
信息: Created JedisPool to master at 127.0.0.1:10003
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

第二次調用selectUserById方法,已經從緩存中取值,再沒有請求DB查詢了

INFO 2017-01-02 23:57:14 http-bio-8080-exec-3 com.bug.controller.user.UserController.login 24-line login method start,the parameter is :
DEBUG 2017-01-02 23:57:15 http-bio-8080-exec-3 org.springframework.cache.interceptor.AbstractFallbackCacheOperationSource.getCacheOperations 109-line Adding cacheable method 'selectUserById' with attribute: [CacheableOperation[public com.bug.model.user.UserVO com.bug.service.user.impl.UserServiceImpl.selectUserById(java.lang.String) throws java.lang.Exception] caches=[user] | key='' | condition='' | unless='']
DEBUG 2017-01-02 23:57:16 http-bio-8080-exec-3 org.springframework.data.redis.core.RedisConnectionUtils.doGetConnection 125-line Opening RedisConnection
DEBUG 2017-01-02 23:57:16 http-bio-8080-exec-3 org.springframework.data.redis.core.RedisConnectionUtils.releaseConnection 205-line Closing Redis Connection
  • 1
  • 2
  • 3
  • 4

自定義Key生成器 
默認生成器是SimpleKeyGenerator,生成的Key是經過HashCode轉換過的,不能通過Key清除指定接口的緩存,因此需要我們自己實現Key生成器,增加Key生成器實現類CacheKeyGenerator,並實現KeyGenerator接口,代碼如下:

public class CacheKeyGenerator implements KeyGenerator {
    @Override
    public Object generate(Object target, Method method, Object... params) {
        StringBuilder key = new StringBuilder();
        key.append(target.getClass().getName());
        key.append(".");
        key.append(method.getName());
        return key.toString();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

這裏Key的生成規則是類的限定名+方法名,可以確保在同一項目中,key不會重名,如果還需要把查詢條件也作爲Key的一部分,可以把params加進來

Key生成器需要配置在applicationContext.xml文件中,如下

<!-- 啓動緩存註解功能,否則緩解不會生效,並自定義Key生成策略  -->
<cache:annotation-driven cache-manager="cacheManager" key-generator="cacheKeyGenerator"/>
<bean id="cacheKeyGenerator" class="com.bug.common.CacheKeyGenerator"></bean>
  • 1
  • 2
  • 3
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章