ShardedJedisPool 中可用連接數的小bug


ShardedJedisPool中,returnBrokenResource() 及 returnResource() ,為施放資源、關閉連接的方法,若重復調用,導致 _numActive 當前活動數一直遞減,會出現負數的情況。

假如在一個方法中設置了三個jedis連接,在獲取第一或第二個連接時出現異常,在拋出異常或者finally中總是施放這三個資源,會導致池中的連接連續施放三次,從而變成負數。

這樣會出現連接池最大連接數配置無效的情況。

 

以下片段代碼:

public class RedisUtil {
    public static ShardedJedisPool pool;
    static {
        JedisPoolConfig config = new JedisPoolConfig();// Jedis池配置
        config.setMaxActive(2);// 最大活動的對象個數
        config.setMaxIdle(1000 * 60);// 對象最大空閑時間
        config.setMaxWait(1000 * 3);// 獲取對象時最大等待時間
        config.setTestOnBorrow(true);
        String hostA = "192.168.0.99";
        int portA = 6380;
        List<JedisShardInfo> jdsInfoList =new ArrayList<JedisShardInfo>(1);
        JedisShardInfo infoA = new JedisShardInfo(hostA, portA);
        jdsInfoList.add(infoA);
        pool = new ShardedJedisPool(config, jdsInfoList);
    }
    
    public static void testRedis() {
        
        ShardedJedis jedis = null;
        ShardedJedis jedis1 = null;
        ShardedJedis jedis2 = null;
        try {
            // 從池中獲取三次連接
            jedis = pool.getResource();
            jedis1 = pool.getResource();
            jedis2 = pool.getResource();
            
            String value = jedis.get("wuse");
            String value1 = jedis1.get("wuse");
            if (null == value || "".equals(value)) {
                jedis.set("wuse", "testWuse");
                jedis.expire("wuse", 20);
            }else {
                System.out.println(value);
            }
        } catch (Exception e) {
            e.printStackTrace();
            
            // 異常時關閉連接,此處可以注釋
        } finally {
            pool.returnBrokenResource(jedis);
            pool.returnBrokenResource(jedis1);
            pool.returnBrokenResource(jedis2);
        }
    }
}

 

比如,設置的最大連接數為3,當第一次獲取連接1和連接2的時候,沒有問題,獲取第三個連接的時候,由於最大連接數為2,所以拋異常

走finally之后,釋放掉三個連接資源,這時候,pool連接池的當前活動數竟然為-1

所以,第二次再調用testRedis()方法時,由於之前pool的活動數為-1,這次三個連接都能獲取成功,不拋異常。

 

-------------------------------------------------------------------------------

ShardedJedisPool類本身繼承Pool類,Pool類中用了org.apache.commons.pool.impl.GenericObjectPool類來當做連接池,而Pool類初始化時,需要傳入PoolableObjectFactory工廠類,在ShardedJedisPool類中自定義了一個繼承BasePoolableObjectFactory類的工廠類ShardedJedisFactory,而ShardedJedisFactory類中的銷毀方法destroyObject()方法中,從傳進來的ShardedJedis對象里獲取了鏡像連接,繼承的最頂層Sharded類中的getAllShards()方法,實際上只是通過Collections工具類獲取了resources的value集合的鏡像,所以實際上也就是說只是意義上釋放了連接。 

而ShardedJedisPool類中的returnBrokenResource()方法,實際上調用的是GenericObjectPool類的invalidateObject()方法,而每次調用后,總會再去做 _numActive --,也就是說,每次調用,當前活動數都會減1,有可能最終導致負數(其實是與實際活動數不匹配),從而影響到原始設定的最大連接數會不管用。

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM