• spring整合redis(哨兵模式)


    首先服务器搭建哨兵模式(我这里使用的是Windows8系统),感谢两位博主,少走不少弯路,在此给出链接:服务器哨兵模式搭建整合哨兵模式

    什么一些介绍就不介绍了,可以看一下连接,比较详细,初次接触,当时很迷茫,特纠结整合时候服务器是否需要开启哨兵模式,因为在整合的时候确认了master,结果很显然是需要的

    先配置服务器(本地)哨兵模式,直接从redis官网下载安装或者解压版,安装后的目录结构

    然后配置哨兵模式

    测试采用3个哨兵,1个主redis,2个从redis。
    复制6份redis.windows.conf文件并重命名如下(开发者可根据自己的开发习惯进行重命名)
    配置master.6378.conf
    port:6379
    #设置连接密码
    requirepass:grs
    #连接密码
    masterauth:grs

    slave.6380.conf配置

    port:6380
    dbfilename dump6380.rdb
    #配置master
    slaveof 127.0.0.1 6379

    slave.6381.conf配置

    port 6381
    slaveof 127.0.0.1 6379
    dbfilename "dump.rdb"

    配置哨兵sentinel.63791.conf(其他两个哨兵配置文件一致,只修改端口号码即可)

    port 63791
    #主master,2个sentinel选举成功后才有效,这里的master-1是名称,在整合的时候需要一致,这里可以随便更改
    sentinel monitor master-1 127.0.0.1 6379 2
    #判断主master的挂机时间(毫秒),超时未返回正确信息后标记为sdown状态
    sentinel down-after-milliseconds master-1 5000
    #若sentinel在该配置值内未能完成failover操作(即故障时master/slave自动切换),则认为本次failover失败。
    sentinel failover-timeout master-1 18000
    #选项指定了在执行故障转移时, 最多可以有多少个从服务器同时对新的主服务器进行同步,这个数字越小,完成故障转移所需的时间就越长
    sentinel config-epoch master-1 2

    需要注意的地方

    1、若通过redis-cli -h 127.0.0.1 -p 6379连接,无需改变配置文件,配置文件默认配置为bind 127.0.0.1(只允许127.0.0.1连接访问)若通过redis-cli -h 192.168.180.78 -p 6379连接,需改变配置文件,配置信息为bind 127.0.0.1 192.168.180.78(只允许127.0.0.1和192.168.180.78访问)或者将bind 127.0.0.1注释掉(允许所有远程访问)

    2、masterauth为所要连接的master服务器的requirepass,如果一个redis集群中有一个master服务器,两个slave服务器,当master服务器挂掉时,sentinel哨兵会随机选择一个slave服务器充当master服务器,鉴于这种机制,解决办法是将所有的主从服务器的requirepass和masterauth都设置为一样。

    3、sentinel monitor master-1 127.0.0.1 6379 2 行尾最后的一个2代表什么意思呢?我们知道,网络是不可靠的,有时候一个sentinel会因为网络堵塞而误以为一个master redis已经死掉了,当sentinel集群式,解决这个问题的方法就变得很简单,只需要多个sentinel互相沟通来确认某个master是否真的死了,这个2代表,当集群中有2个sentinel认为master死了时,才能真正认为该master已经不可用了。(sentinel集群中各个sentinel也有互相通信,通过gossip协议)。

    依次启动redis

    redis-server master.6379.conf

    redis-server slave.6380.conf

    redis-server slave.6381.conf

     

    redis-server sentinel.63791.conf --sentinel(linux:redis-sentinel sentinel.63791.conf)其他两个哨兵也这样启动

    使用客户端查看一下master状态

    查看一下哨兵状态

    现在就可以在master插入数据,所有的redis服务都可以获取到,slave只能读

    整合spring,导入依赖

        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.8.0</version>
        </dependency>
        <!-- spring-redis -->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>1.6.4.RELEASE</version>
        </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
        <version>2.4.2</version>
    </dependency>

    redis.properties

    #redis中心  
    redis.host=127.0.0.1
    #redis.host=10.75.202.11  
    redis.port=6379
    redis.password=  
    #redis.password=123456  
    redis.maxTotal=200
    redis.maxIdle=100
    redis.minIdle=8
    redis.maxWaitMillis=100000
    redis.maxActive=300
    redis.testOnBorrow=true
    redis.testOnReturn=true
    #Idle时进行连接扫描
    redis.testWhileIdle=true
    #表示idle object evitor两次扫描之间要sleep的毫秒数
    redis.timeBetweenEvictionRunsMillis=30000
    #表示idle object evitor每次扫描的最多的对象数
    redis.numTestsPerEvictionRun=10
    #表示一个对象至少停留在idle状态的最短时间,然后才能被idle object evitor扫描并驱逐;这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义
    redis.minEvictableIdleTimeMillis=60000
     
    redis.timeout=100000

    配置sentinel方式一

    <!-- 这个这个bean是继承RedisSentinelConfiguration,原因是我直接使用时,在注入哨兵的时候spring获取不到注入属性的方法,老是报参数异常 -->
        <bean id="redisSentinelConfiguration" class="com.uec.village.redis.RedisConfiguration"><!-- 这里是配置哨兵模式 -->
            <constructor-arg name="sentinels">
                <set>
                    <bean  class="org.springframework.data.redis.connection.RedisNode">
                        <constructor-arg name="host" value="${redis.host}"/>
                        <constructor-arg name="port" value="63791"/>
                    </bean>
                    <bean  class="org.springframework.data.redis.connection.RedisNode">
                        <constructor-arg name="host" value="${redis.host}"/>
                        <constructor-arg name="port" value="63792"/>
                    </bean>
                    <bean  class="org.springframework.data.redis.connection.RedisNode">
                        <constructor-arg name="host" value="${redis.host}"/>
                        <constructor-arg name="port" value="63793"/>
                    </bean>
                </set>
            </constructor-arg>
            <property name="master">
                <bean class="org.springframework.data.redis.connection.RedisNode">
                    <!--必须指定主节点名称,与服务中的master名称一致-->
                    <property name="name" value="master-1"/>
    <!--                 <constructor-arg name="host" value="${redis.host}"/> -->
    <!--                 <constructor-arg name="port" value="6379"/> -->
                </bean>
            </property>
        </bean>
    <!-- 可以直接配置sentinel -->
    <!-- 
    <bean id="redisSentinelConfiguration" class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
        <property name="sentinels">
            <set>
                <bean name="sentinelNode1" class="org.springframework.data.redis.connection.RedisNode">
                    <constructor-arg name="host" value="${redis.host}"/>
                    <constructor-arg name="port" value="63791"/>
                </bean>
                <bean name="sentinelNode2" class="org.springframework.data.redis.connection.RedisNode">
                    <constructor-arg name="host" value="${redis.host}"/>
                    <constructor-arg name="port" value="63792"/>
                </bean>
                <bean name="sentinelNode3" class="org.springframework.data.redis.connection.RedisNode">
                    <constructor-arg name="host" value="${redis.host}"/>
                    <constructor-arg name="port" value="63793"/>
                </bean>
            </set>
        </property>
        <property name="master">
            <bean name="masterNode" class="org.springframework.data.redis.connection.RedisNode">
                <!--必须指定主节点名称-->
                <property name="name" value="mymaster"/>
                <!-- <constructor-arg name="host" value="${redis.host}"/>
                <constructor-arg name="port" value="6379"/>
    -->
            </bean>
        </property>
    </bean>
    -->
    
    
    
    

    配置sentinel方式二

    <bean id="redisSentinelConfiguration" class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
        <constructor-arg name="propertySource" ref="propertySource"/>
    </bean>
    
    <bean name="propertySource" class="org.springframework.core.io.support.ResourcePropertySource">
        <constructor-arg name="location" value="classpath:spring-redis-sentinel.properties" />
    </bean>

    spring-redis-sentinel.properties内容:

    #哨兵监控主redis节点名称,必选
    spring.redis.sentinel.master=mymaster
    #哨兵节点
    spring.redis.sentinel.nodes=192.168.48.31:26379,192.168.48.32:26379,192.168.48.33:26379

    xml配置

    <!-- jedis 配置 -->  
      <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig" >  
             <property name="maxTotal" value="${redis.maxTotal}" />  
             <property name="maxIdle" value="${redis.maxIdle}" />  
             <property name="minIdle" value="${redis.minIdle}" />  
             <property name="maxWaitMillis" value="${redis.maxWaitMillis}" />  
             <property name="testOnBorrow" value="${redis.testOnBorrow}" />  
             <property name="testOnReturn" value="${redis.testOnReturn}" />  
             <property name="testWhileIdle" value="${redis.testWhileIdle}" />  
             <property name="timeBetweenEvictionRunsMillis" value="${redis.timeBetweenEvictionRunsMillis}" />  
             <property name="numTestsPerEvictionRun" value="${redis.numTestsPerEvictionRun}" />  
             <property name="minEvictableIdleTimeMillis" value="${redis.minEvictableIdleTimeMillis}" />  
       </bean >  
      <!-- redis服务器中心 -->  
       <bean id="connectionFactory"  class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" >
                <constructor-arg name="sentinelConfig" ref="redisSentinelConfiguration"/>
             <constructor-arg name="poolConfig" ref="poolConfig" />  
    <!--          <property name="poolConfig" ref="poolConfig" />   如果不是哨兵模式,把这行放开,注释掉上面两行的构造方法注入-->
             <property name="port" value="${redis.port}" />  
             <property name="hostName" value="${redis.host}" />  
             <property name="password" value="${redis.password}" />  
             <property name="timeout" value="${redis.timeout}" ></property>  
       </bean >  
       <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" >  
             <property name="connectionFactory" ref="connectionFactory" />  
             <property name="keySerializer" >  
                 <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />  
             </property>  
             <property name="valueSerializer" >  
                 <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />  
             </property>  
       </bean >  
         
        <!-- cache配置 -->  
       <bean id="redisUtil" class="com.uec.village.util.RedisUtil" >  
             <property name="redisTemplate" ref="redisTemplate" />  
       </bean >  
       <bean id="methodCacheInterceptor" class="com.uec.village.interceptor.MethodCacheInterceptor" >  
             <property name="redisUtil" ref="redisUtil" />  
       </bean >  
      <!-- 配置拦截需要缓存的方法,根绝注解决定 --> <bean id="methodCachePointCut" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" > <property name="advice" > <ref local="methodCacheInterceptor" /> </property> <property name="patterns" > <set> <!-- 确定正则表达式列表 --> <value>com.service.impl...*ServiceImpl.*</value > </set> </property> </bean >

    RedisConfiguration类

    import static org.springframework.util.Assert.notNull;
    
    import java.util.Set;
    
    import org.springframework.data.redis.connection.RedisNode;
    import org.springframework.data.redis.connection.RedisSentinelConfiguration;
    
    public class RedisConfiguration extends RedisSentinelConfiguration{
        
        public RedisConfiguration(){}
        public RedisConfiguration(Iterable<RedisNode> sentinels){
            notNull(sentinels, "Cannot set sentinels to 'null'.");
    
            Set<RedisNode> sentinels2 = getSentinels();
            if(!sentinels2.isEmpty()){
                sentinels2.clear();
            }
    
            for (RedisNode sentinel : sentinels) {
                addSentinel(sentinel);
            }
        }
    
    }

    MethodCacheInterceptor拦截器

    import java.lang.reflect.Method;
    
    import org.aopalliance.intercept.MethodInterceptor;
    import org.aopalliance.intercept.MethodInvocation;
    
    import com.uec.village.annotation.RedisCache;
    import com.uec.village.util.RedisUtil;
    
    /**
     * 用户登录过滤器
     * @author snw
     *
     */
    public class MethodCacheInterceptor implements MethodInterceptor {  
        private RedisUtil redisUtil;  
      
      
        /** 
         * 初始化读取不需要加入缓存的类名和方法名称 
         */  
        public MethodCacheInterceptor() { 
            
        }  
      
        @Override  
        public Object invoke(MethodInvocation invocation) throws Throwable {
            
            Object value = null;  
            String targetName = invocation.getThis().getClass().getName();  
            Method method = invocation.getMethod();
            String methodName = method.getName();  
            RedisCache annotation = method.getAnnotation(RedisCache.class);
            //说明当前方法不需要缓存的,
            if(annotation == null){
                return invocation.proceed();  
            }
            Object[] arguments = invocation.getArguments();  
            String key = getCacheKey(targetName, methodName, arguments);  
            System.out.println(key);  
            try {  
                // 判断是否有缓存  
                if (redisUtil.exists(key)) {  
                    System.out.println("方法名称为:"+methodName+",根据:"+key+",从缓存中获取");
                    return redisUtil.get(key);  
                }  
                // 写入缓存  
                value = invocation.proceed();  
                if (value != null) {  
                    final String tkey = key;  
                    final Object tvalue = value;  
                    if(annotation.isTime()){
                        redisUtil.set(tkey, tvalue);
                        
                    }  
                }  
                return value;
            } catch (Exception e) {  
                e.printStackTrace();  
                if (value == null) {  
                    return invocation.proceed();  
                }  
            }  
            return value;  
        }  
      
        /** 
         * 创建缓存key 
         * 
         * @param targetName 
         * @param methodName 
         * @param arguments 
         */  
        private String getCacheKey(String targetName, String methodName,  
                Object[] arguments) {  
            StringBuffer sbu = new StringBuffer();  
            sbu.append(targetName).append("_").append(methodName);  
            if ((arguments != null) && (arguments.length != 0)) {  
                for (int i = 0; i < arguments.length; i++) {  
                    sbu.append("_").append(arguments[i]);  
                }  
            }  
            return sbu.toString();  
        }  
      
        public void setRedisUtil(RedisUtil redisUtil) {  
            this.redisUtil = redisUtil;  
        }  
     }

    redis工具类

    import java.io.Serializable;
    import java.util.Set;
    import java.util.concurrent.TimeUnit;
    
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.core.ValueOperations;
    
    /**
     * redis工具
     * @author snw
     *
     */
    public class RedisUtil { 
    
        private RedisTemplate<Serializable, Object> redisTemplate;  
      
        /** 
         * 批量删除对应的value 
         *  
         * @param keys 
         */  
        public void remove(final String... keys) {  
            for (String key : keys) {  
                remove(key);  
            }  
        }  
      
        /** 
         * 批量删除key 
         *  
         * @param pattern 
         */  
        public void removePattern(final String pattern) {  
            Set<Serializable> keys = redisTemplate.keys(pattern);  
            if (keys.size() > 0)  
                redisTemplate.delete(keys);  
        }  
      
        /** 
         * 删除对应的value 
         *  
         * @param key 
         */  
        public void remove(final String key) {  
            if (exists(key)) {  
                redisTemplate.delete(key);  
            }  
        }  
      
        /** 
         * 判断缓存中是否有对应的value 
         *  
         * @param key 
         * @return 
         */  
        public boolean exists(final String key) {  
            return redisTemplate.hasKey(key);  
        }  
      
        /** 
         * 读取缓存 
         *  
         * @param key 
         * @return 
         */  
        public Object get(final String key) {  
            Object result = null;  
            ValueOperations<Serializable, Object> operations = redisTemplate  
                    .opsForValue();  
            result = operations.get(key);  
            return result;  
        }  
      
        /** 
         * 写入缓存 
         *  
         * @param key 
         * @param value 
         * @return 
         */  
        public boolean set(final String key, Object value) {  
            boolean result = false;  
            try {  
                ValueOperations<Serializable, Object> operations = redisTemplate  
                        .opsForValue();  
                operations.set(key, value);  
                result = true;  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
            return result;  
        }  
      
        /** 
         * 写入缓存 
         *  
         * @param key 
         * @param value 
         * @return 
         */  
        public boolean set(final String key, Object value, Long expireTime) {  
            boolean result = false;  
            try {  
                ValueOperations<Serializable, Object> operations = redisTemplate  
                        .opsForValue();  
                operations.set(key, value);  
                redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);  
                result = true;  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
            return result;  
        }  
      
        public void setRedisTemplate(  
                RedisTemplate<Serializable, Object> redisTemplate) {  
            this.redisTemplate = redisTemplate;  
        }  
    }

    自定义注解

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface RedisCache { 
        boolean isCache() default false;
    }

    到这里可以测试一下,你缓存的数据,是否可以直接使用客户端获取。如有不对的地方欢迎大家扔鸡蛋,以免误人子弟,谢谢!

  • 相关阅读:
    php在没用xdebug等调试工具的情况下如何让调试内容优雅地展现出来?--php数组格式化
    linux自动定时备份web程序和mysql数据库
    linux下用cronolog分割apache日志
    写在前面--点燃酱爆心中的那团火
    我对知乎前端相关问题的十问十答(转)
    参考美团、饿了么 && localStorage
    vue-scroller的使用 && 开发自己的 scroll 插件
    如何发布一个包到npm && 如何使用自己发布的npm包 && 如何更新发布到npm的package && 如何更新当前项目的包?
    VUE中toast的使用与开发
    如何在vue && webpack 项目中的单文件组件中引入css
  • 原文地址:https://www.cnblogs.com/cunkouzh/p/9242292.html
Copyright © 2020-2023  润新知