Redis中连接池使用的相关问题

http://blog.csdn.net/ouyang111222/article/details/48271007


(一)问题描述:
今天跑了一个storm job,job的目的是向redis写入数据,job可以正常运行,但是奇怪的是运行大约3分钟左右就停了,没有报任何的异常……

(二)问题症结(以下为简化代码):

    @Override
    public void execute(Tuple input) {
       KafkaEvent kafkaEvent = (KafkaEvent) input.getValueByField("kafkaEvent");
       Jedis redis = LoadRedisConfig.getJedis();
       String key=...;//简化
       String value=...;
       redis.hincrBy(key, value, 1l);
    }

 
 

其中LoadRedisConfig为

public class LoadRedisConfig {
    private static Logger logger = LoggerFactory.getLogger(LoadRedisConfig.class);

    private static Jedis jedis=null;
    private static JedisPool jedisPool = null;


     private static int MAX_ACTIVE = 1024;   
     private static int MAX_IDLE = 200;
     private static int MAX_WAIT = 10000;
     private static int TIMEOUT = 10000;
     private static boolean TEST_ON_BORROW = true;

     static{ 
        initRedisPool("**.***.**.**", 6379, null);
     }

     /**
      * 
      * @param host
      * @param port
      * @return
      */
    public static Jedis getJedis(String host,Integer port) {
        jedis=new Jedis(host,port);
        return  jedis;
    }


    /**
     * 获取JedisPoolConfig
     * @return
     */
    public static JedisPoolConfig getJedisPoolConfig(){
          JedisPoolConfig config = new JedisPoolConfig();
          config.setMaxActive(MAX_ACTIVE);
          config.setMaxIdle(MAX_IDLE);
          config.setMaxWait(MAX_WAIT);
          config.setTestOnBorrow(TEST_ON_BORROW);
          return config;
    }



    /**
     * 初始化JedisPool
     * @param host
     * @param port
     * @param password
     * @return
     */
    public static JedisPool initRedisPool(String host,Integer port,String password){
        JedisPoolConfig config=getJedisPoolConfig();
        try{
            jedisPool = new JedisPool(config, host, port, TIMEOUT, password);
        }
        catch(Exception e){
           if(logger.isInfoEnabled()){
               logger.info("jedis pool 初始化连接异常",e.getMessage());
           }    
        }
        return jedisPool;
    }

    /**
     * 获取Jedis实例
     * @return
     */
     public synchronized static Jedis getJedis() {
         try {
             if (jedisPool != null) {
                 Jedis resource = jedisPool.getResource();
                 return resource;
             } else {
                 return null;
            }
         } catch (Exception e) {
             e.printStackTrace();
             return null;
         }
     }

}
 
 
  • 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
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83

(三)问题分析:

(1)通过查找相关的文档发现,刚开始以为是maxclient问题,我查看自己的conf配置发现:

方法1:

cat redis.conf
 
 
  • 1

这里写图片描述

方法2:

config  get *
 
 
  • 1

maxclient解析:

  1. 设置同一时间最大客户端连接数,默认无限制, Redis 可以同时打开的客户端连接数为 Redis 进程可以打开的最大文件描述符数;

  2. 如果设置 maxclients 0 ,表示不作限制;

  3. 当客户端连接数到达限制时, Redis 会关闭新的连接并向客户端返回 max number of clients reached 错误信息。

(2)真正的问题症结:
经过仔细的分析,问题在于我使用了redis的连接池,设置了MAX_ACTIVE为1024,呵呵了….在这里先简要的解释一下:

           JedisPoolConfig config = new JedisPoolConfig();
           //如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态exhausted(耗尽)。
          config.setMaxActive(MAX_ACTIVE);
           //控制一个pool最多有多少个状态为idle(空闲的)的jedis实例。
          config.setMaxIdle(MAX_IDLE);
          //最大等待时间:单位ms
          config.setMaxWait(MAX_WAIT);
          //在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的
          config.setTestOnBorrow(TEST_ON_BORROW);
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

那么问题就找到了:*我在excute中每次都拿到一个redis实例,当实例超过1024之后拿到的redis对象就为null*!

(四)解决问题

(1)解决方法1:将获取redis连接放在prepare中

private Jedis redis;
public void prepare(Map conf, TopologyContext context, OutputCollector collector){
  redis = LoadRedisConfig.getJedis();
}
 
 
  • 1
  • 2
  • 3
  • 4

同时在cleanup()方法中断开连接

    @Override
    public void cleanup() {
        if (redis != null && redis.isConnected()) {
            redis.disconnect();
        }
    } 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

(2)解决方法2:将redis实例返还到连接池

     /**
      * 返还到连接池
      * 
      * @param pool 
      * @param redis
      */
     public static void returnResource(JedisPool pool, Jedis redis) {
         if (redis != null) {
             pool.returnResource(redis);
         }
     }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

推荐两种方法结合使用!


(五)附录:JedisPool常用参数配置

  • maxActive:
    控制一个pool可分配多少个jedis实例;如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态exhausted(耗尽)。
config.setMaxActive(MAX_ACTIVE);
 
 
  • 1
  • maxIdle:
    控制一个pool最多有多少个状态为idle(空闲)的jedis实例;
config.setMaxIdle(MAX_IDLE);
 
 
  • 1
  • minIdle:
    至少有多少个状态为idle(空闲)的jedis实例;默认为0;
config.setMinIdle(minIdle);
 
 
  • 1
  • maxWait:
    表示当borrow一个jedis实例时,最大的等待时间,如果超过等待时间,则直接抛出JedisConnectionException;
config.setMaxWait(MAX_WAIT);
 
 
  • 1
  • testOnBorrow:
    在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;
config.setTestOnBorrow(true);
 
 
  • 1
  • testWhileIdle:
    如果为true,表示有一个idle object evitor线程对idle object进行扫描,如果validate失败,此object会被从pool中drop掉;这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义;默认为false;
config.setTestWhileIdle(false);
 
 
  • 1
  • timeBetweenEvictionRunsMillis:
    表示idle object evitor两次扫描之间要sleep的毫秒数;
config.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
 
 
  • 1
  • whenExhaustedAction:
    控制一个pool最多有多少个状态为idle(空闲)的jedis实例;

whenExhaustedAction:表示当pool中的jedis实例都被allocated完时,pool要采取的操作;默认有三种。
WHEN_EXHAUSTED_FAIL –> 表示无jedis实例时,直接抛出NoSuchElementException;
WHEN_EXHAUSTED_BLOCK –> 则表示阻塞住,或者达到maxWait时抛出JedisConnectionException;
WHEN_EXHAUSTED_GROW –> 则表示新建一个jedis实例,也就说设置的maxActive无用;

config.setWhenExhaustedAction(whenExhaustedAction);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值