Redis 连接池,请高手指点.问题表象Could not get a resource from the pool

wxl1214471 2015-06-12 06:01:16
我写了一个连接池,从池中获取shardedJedis,每次操作之后都会returnResource。当我用1000个线程跑并发时,出现以下问题:

Exception in thread "Thread-733" redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
at redis.clients.util.Pool.getResource(Pool.java:53)
at redis.clients.jedis.ShardedJedisPool.getResource(ShardedJedisPool.java:37)
at com.pcitc.cachems.handler.CacheHandler.getShardedJedis(CacheHandler.java:73)
at com.pcitc.cachems.handler.CacheManagerHandler.<init>(CacheManagerHandler.java:27)
at com.pcitc.cachems.handler.CacheManagerHandler.getInstance(CacheManagerHandler.java:33)
at com.pcitc.cachems.proxy.CacheManagerImpl.<init>(CacheManagerImpl.java:26)
at com.pcitc.cachems.proxy.SellThread.run(TestThreadCache.java:32)
at java.lang.Thread.run(Unknown Source)
Caused by: java.util.NoSuchElementException: Unable to validate object
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:497)
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:360)
at redis.clients.util.Pool.getResource(Pool.java:51)
... 7 more


我的代码如下:

public class CacheHandler {

private Map<String, String> cacheParams;

private static ShardedJedisPool shardedJedisPool = null;

private static CacheHandler instance = new CacheHandler();

public static CacheHandler getInstance(){
return instance;
}

/**
* <p>Title: 私有化默认构造函数</p>
*/
private CacheHandler(){
shardedJedisPool = initShardedJedisPool();
}

public ShardedJedis getShardedJedis(){
return shardedJedisPool.getResource();
}

public Jedis getJedis(){
return shardedJedisPool.getResource().getShard("");
}

public ShardedJedisPool getShardedJedisPool(){
return shardedJedisPool;
}

private ShardedJedisPool initShardedJedisPool(){

getPropertiesByFile();
shardedJedisPool = initJedisShardInfo();

return shardedJedisPool;
}

public void returnResource(ShardedJedis shardedJedis){
if(shardedJedis != null){
shardedJedisPool.returnResource(shardedJedis);
shardedJedis = null;
}
}

public void returnBrokenResource(ShardedJedis shardedJedis){
if(shardedJedis != null){
shardedJedisPool.returnBrokenResource(shardedJedis);
}
}

private Map<String,String> getPropertiesByFile(){
cacheParams = PropertiesUtils.getProMap("redis.properties");
return cacheParams;
}

private JedisPoolConfig initRedisPool(){
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxIdle(Integer.valueOf(cacheParams.get(CacheConstant.MAX_IDLE)).intValue());
config.setMinIdle(Integer.valueOf(cacheParams.get(CacheConstant.MIN_IDLE)).intValue());
config.setMaxTotal(Integer.valueOf(cacheParams.get(CacheConstant.MAX_TOTAL)).intValue());
config.setMaxWaitMillis(Integer.valueOf(cacheParams.get(CacheConstant.MAX_WAIT_MILLS)).longValue());
config.setTestOnBorrow(Boolean.valueOf(cacheParams.get(CacheConstant.TEST_ON_BORRW)).booleanValue());
config.setTestOnReturn(Boolean.valueOf(cacheParams.get(CacheConstant.TEST_ON_RETURN)).booleanValue());
config.setMinEvictableIdleTimeMillis(Integer.valueOf(cacheParams.get(CacheConstant.MIN_EVICTABLE_IDLE_TIME_MILLIS)).longValue());
config.setTimeBetweenEvictionRunsMillis(Integer.valueOf(cacheParams.get(CacheConstant.TIME_BETWEEN_EVICTION_RUNS_MILLIS)).intValue());
config.setBlockWhenExhausted(Boolean.valueOf(cacheParams.get(CacheConstant.BLOCK_WHER_EXHAUSTED)).booleanValue());
config.setJmxEnabled(Boolean.valueOf(cacheParams.get(CacheConstant.JMX_ENABLED)).booleanValue());
config.setNumTestsPerEvictionRun(Integer.valueOf(cacheParams.get(CacheConstant.NUM_TESTS_PER_EVICTION_RUN)).intValue());
config.setTestWhileIdle(Boolean.valueOf(cacheParams.get(CacheConstant.TEST_WHILE_IDLE)).booleanValue());
return config;
}

private ShardedJedisPool initJedisShardInfo(){
List<JedisShardInfo> shards = setJedisShardInfos(cacheParams);
JedisPoolConfig config = initRedisPool();
if(shardedJedisPool == null)
shardedJedisPool = new ShardedJedisPool(config, shards,Hashing.MURMUR_HASH,Sharded.DEFAULT_KEY_TAG_PATTERN);

return shardedJedisPool;
}

private List<JedisShardInfo> setJedisShardInfos(Map<String,String> params){
List<JedisShardInfo> jedisShardInfos = new ArrayList<JedisShardInfo>();
List<String> ips = new ArrayList<String>();
List<String> ports = new ArrayList<String>();

for(Map.Entry<String, String> entry : params.entrySet()){

if(entry.getKey().contains("redis.ip") && entry.getValue() != null)
ips.add(entry.getValue());

if(entry.getKey().contains("redis.port") && entry.getValue() != null)
ports.add(entry.getValue());
}

for(int i=0; i<ips.size(); i++){
String ip = ips.get(i);
String port = ports.get(i);
JedisShardInfo info = new JedisShardInfo(ip, Integer.valueOf(port).intValue(),Integer.valueOf(params.get("redis.timeBetweenEvictionRunsMillis")).intValue(),ip);
String pwd = cacheParams.get("redis.password");
if(VerifyHandler.INSTANCE.isVerify(pwd))
info.setPassword(pwd);
jedisShardInfos.add(info);
}
return jedisShardInfos;
}
}

我定义了一个执行器,用于执行操作并释放资源代码如下:
public abstract class Executor<T> {
private static final Logger logger = LoggerFactory.getLogger(Executor.class);

private ShardedJedis shardedJedis = null;

public Executor(ShardedJedis shardedJedis){
if(!VerifyHandler.INSTANCE.isVerify(shardedJedis)) throw new CacheBaseException("CacheError: Get ShardedJedis is not available from ShardedJedisPool!");
this.shardedJedis = shardedJedis;
}

abstract T execute();

public T getResult(){
T result = null;
try {
result = this.execute();
} catch (Exception e) {
CacheHandler.getInstance().getShardedJedisPool().returnBrokenResource(shardedJedis);
logger.error("CacheError : Redis using occurred error,INFO:"+e.getMessage());
throw new CacheBaseException(e.getMessage());
} finally{
CacheHandler.getInstance().returnResource(shardedJedis);
}

return result;
}
}

public class CacheManagerHandler {
private static final Logger logger = LoggerFactory.getLogger(CacheManagerImpl.class);

private ShardedJedis shardedJedis = CacheHandler.getInstance().getShardedJedis();


private CacheManagerHandler(){}

public static CacheManagerHandler getInstance(){
return new CacheManagerHandler();
}

public boolean set(final byte[] key, final byte[] value) {
return this.set(key, value, CacheConstant.LIFE_TIME);
}

public byte[] get(final byte[] key) {
return new Executor<byte[]>(shardedJedis) {
@Override
byte[] execute(){
if(key.length <= 0) return null;
byte[] bytes = shardedJedis.get(key);
return bytes;
}
}.getResult();

}

}

测试类:
public class TestThreadCache {
public static void main(String[] args) {
for(int i=0; i<1000; i++){

SellThread st = new SellThread(i);
Thread th1 = new Thread(st);
th1.start();
}
}

}

class SellThread implements Runnable {
private int i = 0;
public SellThread(){}

public SellThread(int i){
this.i = i;
}
public void run() {
Object o = CacheManagerHandler.getInstance().get("Company".getBytes());
System.out.println( o +" " +i);
}
}
...全文
2403 2 打赏 收藏 转发到动态 举报
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
SucreKing 2015-12-14
  • 打赏
  • 举报
回复
我在测试的时候会遇到,100并发,第一次很多业务会报错,第二次就没有了。。。。。无语
wxl1214471 2015-06-15
  • 打赏
  • 举报
回复
redis.maxIdle=1500 redis.minIdle=0 redis.maxTotal=1500 redis.maxWaitMills=10000 redis.testOnBorrw=true redis.testOnReturn=true redis.minEvictableIdleTimeMillis=600000 redis.timeBetweenEvictionRunsMillis=5000 redis.blockWhenExhausted=true redis.jmxEnabled=true redis.numTestsPerEvictionRun=50 redis.testWhileIdle=true[/code]

50,530

社区成员

发帖
与我相关
我的任务
社区描述
Java相关技术讨论
javaspring bootspring cloud 技术论坛(原bbs)
社区管理员
  • Java相关社区
  • 小虚竹
  • 谙忆
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧