一、通过JedisPool类实例获取getResource()时抛出can't get a resource异常。
异常代码如下:
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
at redis.clients.util.Pool.getResource(Pool.java:22)
分析:
redis.clients.util.Pool.getResource会从JedisPool实例池中返回一个可用的redis连接。分析源码可知JedisPool extends redis.clients.util.Pool<Jedis> .而Pool<T>是通过
commons-pool开源工具包中的org.apache.commons.pool.impl.GenericObjectPool来实现对Jedis实例的管理的。所以我们分析一下GenericObjectPool或许能找到答案。
首先看一下common-pool的api:http://commons.apache.org/pool/apidocs/index.html?org/apache/commons/pool/impl/GenericObjectPool.html。
其中三个重要个几个属性是: MaxActive: 最大连接数。 MaxIdle: 最大空闲数。 MaxWait: 最大等待时间,单位毫秒(million seconds)。
当连接池中无可用连接时会会进行等待maxWait时间,若超出泽抛Could not get a resource from the pool异常。
所以应根据程序实际情况合理设置这三个参数的值,尽量避免这个异常。
二、对redis进行操作时,抛出redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out异常。
异常代码如下:
redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out
at redis.clients.jedis.Protocol.process(Protocol.java:79)
at redis.clients.jedis.Protocol.read(Protocol.java:131)
at redis.clients.jedis.Connection.getIntegerReply(Connection.java:188)
at redis.clients.jedis.Jedis.sismember(Jedis.java:1266)
分析:
Redis是对内存进行操作,速度应该都在毫秒级,这是我们通常的认识,
那么Redis操作怎么会出现几秒的超时时间?
我们还是先分析一下Jedis的源代码吧,以sadd操作为例:
public Long sadd(final String key, final String... members) {
checkIsInMulti();
client.sadd(key, members);
return client.getIntegerReply();
}
client是redis.clients.jedis.Client.java的实例,继承关系如下:
public class Client extends BinaryClient implements Commands;
public class BinaryClient extends Connection;
Connection包装了对Redis server的socket操作,命令写操作通过socket.getOutputStream()输出流将命令信息发送到redis server,当写完命令后要通过socket.getInputStream()的到的输入流将
命令执行结果返回,这中间必然会有一个命令执行到结果返回的延时时间,这就是一个Jedis调用redis命令操作所用的时间。
需要说明的是,Redis server是单线程执行所有连接发送过来的命令的,也就是说不管并发中有多少个client在发送命令,redis-server端是单线程处理的,并按照默认的FIFO方式处理请求,
这个可在redis.conf配置文件中配置。关于redis server的详细运行机制参见:http://redis.io/documentation
所以client.sadd(key, members);调用完后只是将命令信息发送到了redis server端,具体有没有执行要看redis server的负载情况。然后,通过client.getIntegerReply();等待(time out)返回结果。
Connection初始化socket时有多种选择,其中设置socket time out 的方法如下: