web-dev-qa-db-ja.com

プールからリソースを取得できませんでした(SocketTimeoutException :)

Redis Qからデータにアクセスするために、複数のワーカースレッド(約10)を実行しています。
私はJedis Clientに無限タイムアウトを使用しています。

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

それでも、エラーが発生しています"プールからリソースを取得できませんでした。"スタックトレースを以下に示します。

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
19
Vignesh

Redisが実行されていない場合、この例外がスローされる可能性があります。ただ頭を上げます。

14
Rick Hanlon II

Rick Hanlonの回答に基づいて、Spring BootでRedisを使用している場合にもこの例外がスローされます。

Spring Bootを使用している場合、Redisの依存関係だけでは十分ではありません。また、手動でRedisを redis.io からマシンにダウンロードしてインストールし、それをBashターミナルから実行する必要もあります。

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

サーバーを実行した後、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
5
cst1992

コードが次のような場合:

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

これを試すことができます:

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

これは、Redisのデフォルトのタイムアウト時間は2秒ですが、プログラムはこの時間で実行を終了した可能性があるためです。

3
zks

それは常に起こるのですか、それとも時々起こるのですか?偶発的な場合は、接続プールのサイズを確認することをお勧めします。

JedisPoolConfigを使用している場合、デフォルトの接続プールサイズは 8 です。これはあなたの場合には小さすぎる可能性があります。

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

考えられる原因;

1-Redisサーバーがダウンしているか、Redisアプリケーションが応答していません。

2-アプリケーションはRedisサーバーに接続できません(ファイアウォールなどの問題)。

3-Redisサーバーへの接続がタイムアウトしました。

4-(Redis)プール内のすべての接続は現在ビジーであり、新しい接続を割り当てることはできません。

ケース1と2はインフラ関連です。

ケース3の場合、接続タイムアウトを増やす必要があります( "RedisConnectionTimeout"):

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

ケース4の場合、最大接続数を増やす必要があります( "RedisMaximumActiveConnectionCount"):

poolConfig.setMaxTotal(RedisMaximumActiveConnectionCount); 

以下または類似の実装を想定しています。

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;     
}   
2
Murat

確かではありませんが、Jedisオブジェクトをプールに返さず、redis-serverに接続制限がある可能性があります。

すべてのワーカースレッドは、作業の完了後にJedisインスタンスをプールに返す必要があります。

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