由于最近在考虑使用Redis的消息队列来解决公司领券、积分兑换券的高并发业务场景问题,所以碰到了许多redis使用不当造成的异常,所以分享其中一个异常问题的解决过程。
由于本人是java编写的,所以使用的是jedis,版本为jedis2.2,起初主要使用redis中lpush、rpop、hget、hset进行压力测试,100个线程每个线程循环1000次,比较少出现问题。当我使用hincr、hsetnx等操作时,一直测试十几秒后,就会出现java.net.SocketException: Permission denied: connect错误,起初也是查了搜了许多资料,都比较少提到这种错误。只好去搜索网上redis使用的标准写法,改进自己redis工具类。最后主要是优化redis资源返还的那块代码,之前资源返还时没有使用在异常捕获时的处理块中使用returnBrokenResource进行处理。
按网上一篇博文说的
a、获取jedis实例时,实际上可能有两类错误。
一类是pool.getReource(),得不到可用的jedis实例;
另一类是jedis.set/get时出错也会抛出异常;
为了实现区分,所以根据instance是否为null来实现,如果为空就证明instance根本就没初始化,也就不用return给pool;如果instance不为null,则证明是需要返还给pool的;
b、在instance出错时,必须调用returnBrokenResource返还给pool,否则下次通过getResource得到的instance的缓冲区可能还存在数据,出现问题!
Jedis操作步骤如下:
1->获取Jedis实例需要从JedisPool中获取;
2->用完Jedis实例需要返还给JedisPool;
3->如果Jedis在使用过程中出错,则也需要还给JedisPool;
public long hsetnx(String key, String field,String value) {
long isExist =0;
ShardedJedis shardedJedis =null;
try {
shardedJedis = (ShardedJedis) shardedJedisPool.getResource();//shardedJedisPool为redis链接池
if(shardedJedis != null){
isExist = shardedJedis.hsetnx(key, field, value);
}
}catch (Exception e) {
closeBroken(shardedJedis);//主要添加这个closeBroken方法
e.printStackTrace();
}finally{
close(shardedJedis);
}
return isExist;
}
public void closeBroken(ShardedJedis shardedJedis){
if(shardedJedis!=null&&shardedJedisPool!=null){
shardedJedisPool.returnBrokenResource(shardedJedis);
}
}
public void close(ShardedJedis shardedJedis) {
try {
if(shardedJedis!=null&&shardedJedisPool!=null){
shardedJedisPool.returnResource(shardedJedis);
}
} catch (Exception e) {
e.printStackTrace();
}
}
经过压力测试后没有频繁出现上述连接拒绝的错误
参考博文链接:http://blog.csdn.net/songylwq/article/details/26008327