jedispool连redis高并发卡死的问题

java端在使用jedispool 连接redis的时候,在高并发的时候经常死锁,或报连接异常,JedisConnectionException,或者getResource 异常等各种问题

在使用jedispool 的时候一定要注意两点

1。 在获取 jedisPool和jedis的时候加上线程同步,保证不要创建过多的jedispool 和 jedis

2。 用完Jedis实例后需要返还给JedisPool

整理了一下redis工具类,通过大量测试和高并发测试的

package com.caspar.util;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.log4j.Logger;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
/**
 * Redis 工具类
 * @author caspar
 *
 */
public class RedisUtil { 

  protected static ReentrantLock lockPool = new ReentrantLock();
  protected static ReentrantLock lockJedis = new ReentrantLock(); 

  protected static Logger logger = Logger.getLogger(RedisUtil.class); 

  //Redis服务器IP
  private static String ADDR_ARRAY = FileUtil.getPropertyValue("/properties/redis.properties", "server"); 

  //Redis的端口号
  private static int PORT = FileUtil.getPropertyValueInt("/properties/redis.properties", "port"); 

  //访问密码
//  private static String AUTH = FileUtil.getPropertyValue("/properties/redis.properties", "auth"); 

  //可用连接实例的最大数目,默认值为8;
  //如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。
  private static int MAX_ACTIVE = FileUtil.getPropertyValueInt("/properties/redis.properties", "max_active");; 

  //控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。
  private static int MAX_IDLE = FileUtil.getPropertyValueInt("/properties/redis.properties", "max_idle");; 

  //等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException;
  private static int MAX_WAIT = FileUtil.getPropertyValueInt("/properties/redis.properties", "max_wait");; 

  //超时时间
  private static int TIMEOUT = FileUtil.getPropertyValueInt("/properties/redis.properties", "timeout");; 

  //在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;
  private static boolean TEST_ON_BORROW = FileUtil.getPropertyValueBoolean("/properties/redis.properties", "test_on_borrow");; 

  private static JedisPool jedisPool = null; 

  /**
   * redis过期时间,以秒为单位
   */
  public final static int EXRP_HOUR = 60*60;     //一小时
  public final static int EXRP_DAY = 60*60*24;    //一天
  public final static int EXRP_MONTH = 60*60*24*30;  //一个月 

  /**
   * 初始化Redis连接池
   */
  private static void initialPool(){
    try {
      JedisPoolConfig config = new JedisPoolConfig();
      config.setMaxTotal(MAX_ACTIVE);
      config.setMaxIdle(MAX_IDLE);
      config.setMaxWaitMillis(MAX_WAIT);
      config.setTestOnBorrow(TEST_ON_BORROW);
      jedisPool = new JedisPool(config, ADDR_ARRAY.split(",")[0], PORT, TIMEOUT);
    } catch (Exception e) {
      logger.error("First create JedisPool error : "+e);
      try{
        //如果第一个IP异常,则访问第二个IP
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(MAX_ACTIVE);
        config.setMaxIdle(MAX_IDLE);
        config.setMaxWaitMillis(MAX_WAIT);
        config.setTestOnBorrow(TEST_ON_BORROW);
        jedisPool = new JedisPool(config, ADDR_ARRAY.split(",")[1], PORT, TIMEOUT);
      }catch(Exception e2){
        logger.error("Second create JedisPool error : "+e2);
      }
    }
  } 

  /**
   * 在多线程环境同步初始化
   */
  private static void poolInit() {
    //断言 ,当前锁是否已经锁住,如果锁住了,就啥也不干,没锁的话就执行下面步骤
    assert ! lockPool.isHeldByCurrentThread();
    lockPool.lock();
    try {
      if (jedisPool == null) {
        initialPool();
      }
    }catch(Exception e){
      e.printStackTrace();
    } finally {
      lockPool.unlock();
    }
  } 

  public static Jedis getJedis() {
    //断言 ,当前锁是否已经锁住,如果锁住了,就啥也不干,没锁的话就执行下面步骤
    assert ! lockJedis.isHeldByCurrentThread();
    lockJedis.lock(); 

    if (jedisPool == null) {
      poolInit();
    }
    Jedis jedis = null;
    try {
      if (jedisPool != null) {
        jedis = jedisPool.getResource();
      }
    } catch (Exception e) {
      logger.error("Get jedis error : "+e);
    }finally{
      returnResource(jedis);
      lockJedis.unlock();
    }
    return jedis;
  }  

  /**
   * 释放jedis资源
   * @param jedis
   */
  public static void returnResource(final Jedis jedis) {
    if (jedis != null && jedisPool !=null) {
      jedisPool.returnResource(jedis);
    }
  } 

  /**
   * 设置 String
   * @param key
   * @param value
   */
  public synchronized static void setString(String key ,String value){
    try {
      value = StringUtil.isEmpty(value) ? "" : value;
      getJedis().set(key,value);
    } catch (Exception e) {
      logger.error("Set key error : "+e);
    }
  } 

  /**
   * 设置 过期时间
   * @param key
   * @param seconds 以秒为单位
   * @param value
   */
  public synchronized static void setString(String key ,int seconds,String value){
    try {
      value = StringUtil.isEmpty(value) ? "" : value;
      getJedis().setex(key, seconds, value);
    } catch (Exception e) {
      logger.error("Set keyex error : "+e);
    }
  } 

  /**
   * 获取String值
   * @param key
   * @return value
   */
  public synchronized static String getString(String key){
    if(getJedis() == null || !getJedis().exists(key)){
      return null;
    }
    return getJedis().get(key);
  }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

您可能感兴趣的文章:

  • Jedis对redis的五大类型操作代码详解
  • java基于jedisLock—redis分布式锁实现示例代码
  • Java使用Jedis操作Redis服务器的实例代码
  • Java客户端利用Jedis操作redis缓存示例代码
  • Redis 订阅发布_Jedis实现方法
  • jedis操作redis的几种常见方式总结
  • Java中使用Jedis操作Redis的实现代码
  • java客户端Jedis操作Redis Sentinel 连接池的实现方法
  • Java中使用Jedis操作Redis的示例代码
  • Jedis操作Redis数据库的方法
(0)

相关推荐

  • Java中使用Jedis操作Redis的实现代码

    一.   redis的安装 1.下载源码,解压缩后编译源码. [root@cwt123 ~]# tar xzf redis-2.8.3.tar.gz [root@cwt123 ~]# cd redis-2.8.3 [root@cwt123 ~]# make 2.启动Redis服务.(src在redis-2.8.3下) [root@cwt123 ~]# cd src [root@cwt123 ~] ./redis-server 3.连接redis客户端 [root@cwt123 ~]# ./red

  • Java客户端利用Jedis操作redis缓存示例代码

    前言 Redis是一个开源的Key-Value数据缓存,和Memcached类似.Redis多种类型的value,包括string(字符串).list(链表).set(集合).zset(sorted set --有序集合)和hash(哈希类型). Jedis 是 Redis 官方首选的 Java 客户端开发包.下面就来给大家详细关于Java客户端利用Jedis操作redis缓存的相关内容,话不多说,直接来看示例代码吧. 示例代码: //连接redis ,redis的默认端口是6379 Jedis

  • Java中使用Jedis操作Redis的示例代码

    使用Java操作Redis需要jedis-2.1.0.jar,下载地址:jedis-2.1.0.jar 如果需要使用Redis连接池的话,还需commons-pool-1.5.4.jar,下载地址:commons-pool-1.5.4.jar package com.test; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.j

  • Java使用Jedis操作Redis服务器的实例代码

    这几天Java项目中需要用到Redis,于是学习了一下使用Jedis来操作Redis服务器的相关知识,下面为具体的配置和代码. 1.Maven中配置Jedis 在maven项目的pom.xml中添加依赖 <dependencies> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</

  • Jedis操作Redis数据库的方法

    本文实例为大家分享了Jedis操作Redis数据库的具体代码,供大家参考,具体内容如下 关于NoSQL的介绍不写了,直接上代码 第一步导包,不多讲 基本操作: package demo; import org.junit.Test; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; public class Demo

  • jedis操作redis的几种常见方式总结

    前言 Redis是一个著名的key-value存储系统,也是nosql中的最常见的一种.其实,个人认为,redis最强大的地方不在于其存储,而在于其强大的缓存作用. 我们可以把它想象成一个巨大的(多借点集群,聚合多借点的内存)的Map,也就是Key-Value. 所以,我们可以把它做成缓存组件. 官方推荐的Java版客户端是jedis,非常强大和稳定,支持事务.管道及有jedis自身实现.我们对redis数据的操作,都可以通过jedis来完成. 那我们就来看一看,jedis不同的调用方式: (1

  • Jedis对redis的五大类型操作代码详解

    本篇主要阐述Jedis对redis的五大类型的操作:字符串.列表.散列.集合.有序集合. JedisUtil 这里的测试用例采用junit4进行运行,准备代码如下: private static final String ipAddr = "10.10.195.112"; private static final int port = 6379; private static Jedis jedis= null; @BeforeClass public static void init

  • java客户端Jedis操作Redis Sentinel 连接池的实现方法

    pom.xml配置 <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.0.2.RELEASE</version> </dependency> <dependency> <groupId>redis.clients<

  • java基于jedisLock—redis分布式锁实现示例代码

    分布式锁是啥? 单机锁的概念:我们正常跑的单机项目(也就是在tomcat下跑一个项目不配置集群)想要在高并发的时候加锁很容易就可以搞定,java提供了很多的机制例如:synchronized.volatile.ReentrantLock等锁的机制. 为啥需要分布式锁:当我们的项目比较庞大的时候,单机版的项目已经不能满足吞吐量的需求了,需要对项目做负载均衡,有可能还需要对项目进行解耦拆分成不同的服务,那么肯定是做成分布式的项目,分布式的项目因为是不同的程序控制,所以使用java提供的锁并不能完全保

  • Redis 订阅发布_Jedis实现方法

    我想到使用Redis的订阅发布模式是用来解决推送问题的-. 对于概念性的叙述,多多少少还是要提一下的: 什么是Redis发布订阅?Redis发布订阅是一种消息通信模式,发送者通过通道A发送消息message,订阅过通道A的客户端就可以接收到消息message.嗯度娘上面的解释要比我所说的好多了,而我所理解的就是:所谓的订阅发布模式,其实和我们看电视,听广播差不多,在我们没有调台(换频道)的时候,那个频道也是在传递消息的(发布).我们换到那个频道上(订阅)就能接收到消息了.是的,虽然可能有些不恰当

随机推荐