Redis开发记录

Redis哨兵连接池初始化开发记录

最近在redis的测试,总是不如意,在单节点测试,可以通过,加入哨兵后,也可以通过,但是加入连接池后就一直报错,各种错误,很苦恼,去掉哨兵只加入连接池,也是不报错的,可以通过,但是需要的目的效果是加入哨兵和连接池并初始化连接池。经过这几天的调试查阅资料,总算4.7晚跑通。记录一下错误和自己心得吧。

 

 

原先代码

首先,写好redis加载哨兵的配置,以查询一个string的值为例。

最初我是这样写的(注意:这时候是没有连接池的概念和初始化连接池的)

//开启连接

@SuppressWarnings("deprecation")

public static JedisSentinelPool ConnectRedis() {

//加入哨兵

    if(redisSentinelJedisPool==null) {

     System.out.println("redisSentinelJedisPool为空,新建连接池");

    Set<String> sentinels = new HashSet<String>();

      String hostAndPort1 = "47.100.97.xxx:26379";

      String hostAndPort2 = "47.100.2.xxx:26379";

      String hostAndPort3 = "106.14.171.xxx:26379";

       sentinels.add(hostAndPort1);

       sentinels.add(hostAndPort2);

       sentinels.add(hostAndPort3);

       String clusterName = "mymaster";

       String password = "ymylxxxx";

       JedisSentinelPool redisSentinelJedisPool = new JedisSentinelPool("mymaster",sentinels,"ymylxxxx");

       return redisSentinelJedisPool;

     } else {

     System.out.println("redisSentinelJedisPool不为空,直接返回");

     return redisSentinelJedisPool;

     }

      }

写了一个连接的方法,在里面写了加载哨兵,密码之类的,并且做了判断,redisSentinelJedisPool为空时就加载。反之就不用加载。

之后在写业务时候直接先调用这个连接的方法。

public static String GetRedisString(String key) {

     JedisSentinelPool redisSentinelJedisPool=ConnectRedis();

        Jedis jedis = null;

        String object = null;

         try {

             jedis = redisSentinelJedisPool.getResource();

             //读取

             object =jedis.get(key);

             System.out.println(object);

         } catch (Exception e) {

            e.printStackTrace();

         } finally {

            //方法归还

          //redisSentinelJedisPool.returnResource(jedis);  

          jedis.close();

        }

return object;

    }

这是一个查询redis缓存中一个string类型的一个值。

没问题,是可以跑通的,也正常拿到自己需要的key的值。但是测试时候发现,很容易崩溃。发现没我查询每一次都会去连接,很耗费时间资源,应该加入连接池的概念,只需要第一次启动时候连接并初始化连接池,之后就不用,直接去做具体业务就可以,这样就会大大减少时间。

修改后,加入连接池(可根据自己业务需求定义初始化数据):

 

/**

     *  初始化Redis连接池.

     */

    static {

     System.out.println("初始化连接池");

        JedisPoolConfig config = new JedisPoolConfig();

        //设置最大连接总数

        config.setMaxTotal(300);

        //设置最大空闲数

        config.setMaxIdle(50);

        //设置最小空闲数

        config.setMinIdle(8);

        config.setMaxWaitMillis(10000);

        //在获取连接的时候检查有效性, 默认false

        config.setTestOnBorrow(true);

        //在空闲时检查有效性, 默认false

        config.setTestOnReturn(true);

        //是否启用pool的jmx管理功能, 默认true

        config.setJmxEnabled(true);

        //Idle时进行连接扫描

        config.setTestWhileIdle(true);

        //是否启用后进先出, 默认true

        config.setLifo(true);

        //逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1

        config.setTimeBetweenEvictionRunsMillis(30000);

        //每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3

        config.setNumTestsPerEvictionRun(10);

        //表示一个对象至少停留在idle状态的最短时间,然后才能被idle object evitor扫描并驱逐;这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义

        config.setMinEvictableIdleTimeMillis(60000);

        //连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true

        config.setBlockWhenExhausted(true);

        //对象空闲多久后逐出, 当空闲时间>该值 且 空闲连接>最大空闲数 时直接逐出,不再根据MinEvictableIdleTimeMillis判断  (默认逐出策略)

        config.setSoftMinEvictableIdleTimeMillis(1800000);

        System.out.println("初始化结束");

然后再加入哨兵机制

Set<String> set = new HashSet<>();

        //连接地址以及端口号,有多个就一次增加

        set.add("47.100.97.xxx:26379");

        set.add("47.100.2.xxx:26379");

        set.add("106.14.171.xxx:26379");

        jedisSentinelPool = new JedisSentinelPool("mymaster", set, config,"ymylxxxx");

        System.out.println("加载哨兵完成");

获取实例

/**

     * 获取Jedis实例

     * @return 返回Jedis实例

     */

    public synchronized static Jedis getJedis() {

        try {

            if (jedisSentinelPool != null) {

             System.out.println("连接池不为空");

                return jedisSentinelPool.getResource();

            } else {

                return null;

            }

        } catch (Exception e) {

            e.printStackTrace();

            return null;

        }

    }

释放资源

/**

     * 释放资源.

     * @param jedis jedis

     */

    public static void releaseResource(final Jedis jedis) {

        if (jedis != null){

            jedis.close();

            //jedisSentinelPool.destroy();

        }

    }

业务逻辑:取一个string的值

/*

    * 查询String类型

    */

    public static String GetRedisString(String key) {

        Jedis jedis = null;

        String object = null;

         jedis = getJedis();

             //读取

         System.out.println("开始读取key");

             object =jedis.get(key);

             System.out.println(object);

            //方法归还

          releaseResource(jedis);

return object;

    }

    

 

这种是直接在代码中加载连接池并初始化。另一种方法是也可以写在加载文件配置中直接交给spring去处理,下面记录一下在使用spring配置时候的错误和记录。

<!--配置Jedis连接池-->

<!-- 引入属性文件,在配置中占位使用 -->

1、首先加载你的属性文件(redis.properties),我是直接把值写进去没用属性文件,所以不用加载,注释掉,根据个人需要吧。

 <!--<context:property-placeholder location="classpath:redis.properties" ignore-resource-not-found="true" />  -->  

设置一系列参数,

<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">

        <property name="maxTotal" value="5000" />

        <property name="minIdle" value="5" />

        <property name="maxWaitMillis" value="3000" />

        <property name="maxIdle" value="20" />

        <property name="testOnBorrow" value="true" />

        <property name="testOnReturn" value="true" />

</bean>

     <beanid="jedisSentinelPool" class="redis.clients.jedis.JedisSentinelPool">

     <beanid="jedisSentinelPool" class="redis.clients.jedis.JedisSentinelPool">

        <constructor-arg index="0" value="mymaster" />

        <constructor-arg index="1">

       设置你的哨兵端口,有几个写几个。   

  <set>

                 <value>106.14.171.xxx:6379</value>

                 <value>47.100.97.xxx:6379</value>

                 <value>47.100.2.xxx:6379</value>

            </set>

        </constructor-arg>

        <constructor-arg index="2" ref="poolConfig" />

如果有密码就在这里加上你的密码

       <constructor-arg index="3" value="ymylxxxx" />

</bean>

 

 然后注入redis工具类

  <bean  class="com.manager.util.RedisUtil">

<property name="jedisSentinelPool" ref="jedisSentinelPool"/>

</bean>

我这样写了后,刚开始使用属性文件的,在我的目录下创建了redis.properties,里面设置各种参数,和我 <property name="maxTotal" value="${redis.maxTotal}" />对应,

利用

<context:property-placeholder location="classpath:redis.properties" ignore-resource-not-found="true" />直接加载进来,获取属性文件中的参数。但是这时候运行起来却报错了,发现和我的数据库读取属性文件发生冲突。如何解决这个冲突,之后再谈。

然后我尝试直接在配置中吧参数写进去,如上面的代码。

这样就不需要去加载属性文件读取参数,这样就避免了和数据库读取属性文件的冲突。

Ok准备就绪,运行起来,又报错了,一直提示我所有的哨兵down,但是查看后哨兵都没有down,很奇怪。上网查询资料,也一直没能解决。(为了不拖延项目进度,关于spring配置方法继续再查资料,一定写通)所以就尝试另一种方法写,没有用spring配置来写,选择用代码直接初始化连接池。代码实例就是一开始最初的代码,

 

错误注意:考虑之前错误提示所有哨兵down,仔细想了一下,可能是我既在配置中设置了连接池初始化和加载了哨兵,又在代码中设置了,起了冲突。(应该是这个,下班回家测试下。)

 

但是后来考虑到一个问题,因为我现在是把初始化连接池带参数写在redisutil类的代码中,这样的话,如果我没有用到这个业务,没有用到这个redisutil类的话。我的连接池就没有初始化,但是其实一细想,也没关系,不用redis 的话就不会用到连接池了,所以没什么关系,放到spring配置中,是应该算是项目一启动就开启了连接池并初始化了。

总算是在不懈努力下吧,算是跑通了业务,但是对于redis还是有很多东西不是很理解,需要多看看资料了解,缓存是一个很重要的东西,能和数据库一般的存在,当然不是那么简单啦,继续努力吧少年!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值