`

关于jedispool大并发时遇到JedisConnectionException的解决方案

 
阅读更多

每次遇到JedisConnectionException这个异常,jedispool就崩溃了,总结问题:有可能是阿里云的服务器老是会掉线,掉线这个问题不止一次遇见了,但也有可能是其它问题;这个问题很严重;为了系统有更好的容灾性,然后就有下面的歪招了;

下面是源码
import org.apache.log4j.Logger;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Transaction;
import redis.clients.jedis.exceptions.JedisConnectionException;


/**
* 工程内不准在其它类调用redis操作,只能在该类.
* 这样的好处是避免了Jedis忘记回收,导致宕机;特别是加了分布式锁的时候,后果是整个集群宕机,当然一般人都没那么笨,锁不加时效,呵....
* @author lyq
*
* @param <T>
*/

public abstract class RedisExecutor<T> {
int errorCount = 0;
protected static final Logger log =  Logger.getLogger(RedisExecutor.class);
static Boolean isPass = false;
public JedisPool jedisPool = null;
public Jedis jedis = null;
public Transaction tran = null;
private static LatchControl mylatch = new LatchControl(10000L);
// public RedisExecutor(JedisPool pool){
// this.jedisPool = pool;
// }

public RedisExecutor(){
//整个RedisManager是单例,jedisPool也是单例
this.jedisPool = RedisManager.getInstance().getJedisPool();
}

public T exec() throws PiRedisExecption{
boolean isCatch = false;
try{
//该应用所有线程过来遇到jedispool崩溃了,就是遇到JedisConnectionException,线程就会等待,停到这里。等待某个线程处理完jedispool的异常,再执行。

mylatch.waitLatch();
jedis = jedisPool.getResource();
return run();
}catch(Exception e){
isCatch = true;
if(jedis!=null){
this.jedisPool.returnBrokenResource(jedis);
}
if(tran!=null){
tran.discard();
}
if(e instanceof JedisConnectionException){
errorCount++;
log.info("new jedis pool :"+isPass);
isPass = false;
synchronized (mylatch) {
if(!isPass){
try {
//唤醒锁让所有redis的执行的等待
mylatch.wakeupWait();
RedisManager.getInstance().destoryPool();
isPass = true;
mylatch.countDown();//开锁,所有redis操作继续
log.info("open lock~~~");
} catch (InterruptedException e1) {
throw new RuntimeException(e);
}
}
log.info("execute again!!!!!!!!!!");
}
jedisPool = RedisManager.getInstance().getJedisPool();
// jedis = jedisPool.getResource();
if(errorCount<5){
return exec();//在新的jedispool下再跑一遍
}else{
throw new PiRedisExecption(e);
}

}
return null;
// throw new PiRedisExecption(e);
}finally{
if(jedis!=null&&(!isCatch)){
this.jedisPool.returnResource(jedis);
}
}
}

public abstract T run() throws Exception;


}


下面这个类是CountDownLatch的扩展,在执行过程中CountDownLatch.await()是主动执行等待,那么这个类的waitLatch是被动执行等待;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* LatchControl是CountDownLatch的被动式
* @author lyq
*
*/
public class LatchControl {
Long timeout = 1L;
public LatchControl(Long timeout){
this.timeout = timeout;
}

public CountDownLatch latch = null;

public void waitLatch() throws InterruptedException{
if(latch!=null){
latch.await(this.timeout*2,TimeUnit.MILLISECONDS);
}
}

public void wakeupWait() throws InterruptedException{
latch = new CountDownLatch(1);
Thread.sleep(this.timeout);
}
public void countDown(){
latch.countDown();
latch = null;
}

}

然后关于jedis的调用,绝对不会忘掉回收jedis;或者遇到JedisConnectionException挂掉整个应用;
new RedisExecutor<Boolean>() {
@Override
public Boolean run() throws Exception {
                              //tran = jedis.multi();需要使用redis事务时
if(jedis.zcard(keyName)==0){
jedis.del(keyName);
return true;
}
                            // tran.exec();
return false;
}
}.exec();
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics