web-dev-qa-db-fra.com

Impossible d'obtenir une ressource du pool (SocketTimeoutException :)

J'utilise plusieurs threads de travail (environ 10) pour accéder aux données du redis Q.
J'utilise un délai infini pour Jedis Client

Jedis jedis = pool.getResource();
jedis.getClient().setTimeoutInfinite();  

Je reçois toujours l'erreur "Impossible d'obtenir une ressource du pool". Le stacktrace est donné ci-dessous. 

redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
at redis.clients.util.Pool.getResource(Pool.Java:22)
at Workers.Worker1.met1(Worker1.Java:124)
at Workers.Worker1.work(Worker1.Java:108)
at org.gearman.impl.worker.WorkerConnectionController$3.run(Unknown Source)
at Java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at Java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at Java.lang.Thread.run(Unknown Source)  

Caused by: redis.clients.jedis.exceptions.JedisConnectionException: Java.net.SocketTimeoutException: connect timed out
at redis.clients.jedis.Connection.connect(Connection.Java:124)
at redis.clients.jedis.BinaryClient.connect(BinaryClient.Java:54)
at redis.clients.jedis.BinaryJedis.connect(BinaryJedis.Java:1657)
at redis.clients.jedis.JedisPool$JedisFactory.makeObject(JedisPool.Java:63)
at org.Apache.commons.pool.impl.GenericObjectPool.borrowObject(GenericObjectPool.Java:1188)
at redis.clients.util.Pool.getResource(Pool.Java:20)
... 6 more  

Caused by: Java.net.SocketTimeoutException: connect timed out
at Java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
at Java.net.DualStackPlainSocketImpl.socketConnect(Unknown Source)
at Java.net.AbstractPlainSocketImpl.doConnect(Unknown Source)
at Java.net.AbstractPlainSocketImpl.connectToAddress(Unknown Source)
at Java.net.AbstractPlainSocketImpl.connect(Unknown Source)
at Java.net.PlainSocketImpl.connect(Unknown Source)
at Java.net.SocksSocketImpl.connect(Unknown Source)
at Java.net.Socket.connect(Unknown Source)
at redis.clients.jedis.Connection.connect(Connection.Java:119)
... 11 more
16
Vignesh

J'ai remarqué que cette exception peut et sera levée si Redis n'est pas en cours d'exécution. Juste un heads-up.

10
Rick Hanlon II

Basé sur la réponse de Rick Hanlon, cette exception est également levée si vous utilisez Redis avec Spring Boot.

Si vous utilisez Spring Boot, la dépendance de Redis ne suffit pas; vous devez également télécharger et installer manuellement Redis sur votre ordinateur à partir de redis.io , puis exécutez-le depuis un terminal Bash:

me@my_pc:/path/to/redis/dir$ ./src/redis-server ./redis.conf

Après avoir exécuté le serveur, vous devez ajouter les lignes appropriées dans toutes vos applications utilisant Redis:

application.properties:

...
spring.redis.Host: <yourhost> // usually localhost, but can also be on a LAN
spring.redis.port: <yourport> // usually 6379, but settable in redis.conf

application.yml:

...
spring:
  redis:
    Host: <yourhost> // usually localhost, but can also be on a LAN
    port: <yourport> // usually 6379, but settable in redis.conf
4
cst1992

Si votre code est comme ça: 

JedisPoolConfig jedisPoolConfig = initPoolConfig();    
jedisPool = new JedisPool(jedisPoolConfig, "*.*.*.*", 6379);  

Vous pouvez essayer ceci: 

JedisPoolConfig jedisPoolConfig = initPoolConfig();    
jedisPool = new JedisPool(jedisPoolConfig, "*.*.*.*", 6379,10*1000); 

En effet, pour Redis, le délai d'attente par défaut est de 2 secondes, mais le programme a peut-être fini de s'exécuter dans ce délai.

3
zks

Pas sûr, mais peut-être que vous ne renvoyez pas d'objets Jedis au pool et que votre serveur Redis a un nombre limité de connexions.

Chaque thread de travail doit renvoyer les instances Jedis au pool une fois son travail terminé:

Jedis jedis = jedisPool.getResource();
try {
    jedis.getClient().setTimeoutInfinite();
    // your code here...
    ...
} finally {
    jedisPool.returnResource(jedis);
}
1
Jarek

Cela s'est-il toujours produit ou occasionnellement? Si c'était occasionnel, vous pouvez vérifier la taille de votre pool de connexions. 

La taille du pool de connexions par défaut, si vous utilisez JedisPoolConfig, est 8 . Cela pourrait être trop petit pour votre cas.

JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(128);
jedisPool = new JedisPool(poolConfig, Host, PORT, ...);

Causes possibles;

1 - Le serveur Redis est en panne ou l’application Redis ne répond pas.

2 - L'application ne peut pas se connecter au serveur Redis (problèmes de pare-feu, etc.).

3 - La connexion au serveur Redis a expiré.

4 - Toutes les connexions du pool (Redis) sont actuellement occupées, une nouvelle connexion ne peut pas être attribuée.

Les cas 1 et 2 sont liés entre eux. 

Pour le cas 3, le délai de connexion doit être augmenté ("RedisConnectionTimeout"):

pool = new pool(poolConfig, RedisIp, RedisPort, RedisConnectionTimeout);

Dans le cas 4, le nombre maximal de connexions doit être augmenté ("RedisMaximumActiveConnectionCount"):

poolConfig.setMaxTotal(RedisMaximumActiveConnectionCount); 

En supposant la mise en œuvre suivante ou similaire;

private Pool<Jedis> pool =  null;   

private final String RedisIp="10.10.10.11";
private final int RedisPort=6379;
private final String RedisConnectionTimeout=2000;
private final String RedisMaximumWaitTime=1000;
private final String RedisMaximumIdleConnectionCount=20;
private final String RedisMaximumActiveConnectionCount=300;
private final String SentinelActive=false;
private final String SentinelHostList="10.10.10.10:26379,10.10.10.10:26380,10.10.10.10:26381";
private final String SentinelMasterName="sentinel-master-name";

private synchronized void initializePool()
{
    if(pool!=null) return;

    poolConfig poolConfig = new poolConfig();
    poolConfig.setMaxTotal(RedisMaximumActiveConnectionCount); 
    poolConfig.setMaxIdle(RedisMaximumIdleConnectionCount);  
    poolConfig.setMaxWaitMillis(RedisMaximumWaitTime); 

    if(SentinelActive)
    {
        String [] sentinelsArray = SentinelHostList.split(",");

        Set<String> sentinels = new HashSet<>();            
        for(String sentinel : sentinelsArray)
        {
            sentinels.add(sentinel);
        }

        String masterName = SentinelMasterName;

        pool = new JedisSentinelPool(masterName, sentinels, poolConfig, RedisConnectionTimeout);            
    }
    else
    {       
        pool = new pool(poolConfig, RedisIp, RedisPort, RedisConnectionTimeout);
    }

}           

protected Jedis getConnection()
{               
    if(pool==null)
        initializePool();

      Jedis jedis = pool.getResource();

      return jedis;     
}   
0
Murat