轉載自:http://blog.csdn.net/fachang/article/details/7984123
異常代碼如下:
- Could not get a resource from the pool
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: 空閑連接實例的最大數目,為負值時沒有限制。Idle的實例在使用前,通常會通過org.apache.commons.pool.BasePoolableObjectFactory<T>的activateObject()方法使其變得可用。
MaxWait: 等待可用連接的最大數目,單位毫秒(million seconds)。
(注:pool.getResource()方法實際調用的GenericObjectPool類borrowObject()方法,該方法會根據MaxWait變量值在沒有可用連接(idle/active)時阻塞等待知道超時,具體含義參看api。)
也就是說當連接池中沒有active/idle的連接時,會等待maxWait時間,如果等待超時還沒有可用連接,則拋出Could not get a resource from the pool異常。所以為避免這樣的錯誤,
我們應該根據程序實際情況合理設置這三個參數的值,同時在我們獲取一個連接的程序方法中也應該合理的處理這個異常,當沒有連接可用時,等待一段時間再獲取也許是個比較好的選擇。
- 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 的方法如下:
- public void rollbackTimeout() {
- try {
- socket.setSoTimeout(timeout);
- socket.setKeepAlive(false);
- } catch (SocketException ex) {
- throw new JedisException(ex);
- }
- }
由redis.clients.jedis.Protocol.DEFAULT_TIMEOUT = 2000;所以可以考慮把超時時間設長,但需要選個合理的值,否則服務可能會堵塞在這個步驟。