【问题标题】:Could not get a resource from the pool(SocketTimeoutException:)无法从池中获取资源(SocketTimeoutException:)
【发布时间】:2012-10-14 03:57:44
【问题描述】:

我正在运行多个工作线程(大约 10 个)来访问来自 redis Q 的数据。
对于我正在为 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

【问题讨论】:

  • 你的 Redis 服务器还活着吗?您可以使用 redis-cli 从客户端框连接到它吗?
  • 是的 Redis 服务器是活动的并且能够使用 redis-cli 连接
  • 我也有同样的问题。 Redis 正在运行。使用 JedisPool 时会出现问题,我使用 returnResourceJedis jedis = new Jedis("localhost"); 没问题。你解决了这个问题吗?

标签: java redis socketexception jedis


【解决方案1】:

我注意到如果 Redis 没有运行,这个异常可以并且将会被抛出。请注意。

【讨论】:

    【解决方案2】:

    根据 Rick Hanlon 的回答,如果将 Redis 与 Spring Boot 一起使用,也会引发此异常。

    如果你使用的是Spring Boot,仅仅依赖Redis是不够的;您还需要从 redis.io 手动下载并在您的计算机上安装 Redis,然后从 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
    

    【讨论】:

    • 是否需要安装redis,即使连接到远程redis实例?
    • @zookastos 不,不是
    • 感谢后来通过阅读更多文档发现了这一点。这是一个愚蠢的问题:)
    【解决方案3】:

    它是一直发生还是偶尔发生?如果是偶尔,您可能需要检查连接池的大小。

    如果您使用JedisPoolConfig,默认连接池大小为8。对于您的情况,这可能太小了。

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

    【讨论】:

    【解决方案4】:

    可能的原因;

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

    【讨论】:

      【解决方案5】:

      如果你的代码是这样的:

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

      你可以试试这个:

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

      这是因为 Redis 默认的超时时间是 2 秒,但程序可能在这个时间内运行完毕。

      【讨论】:

        【解决方案6】:

        不确定,但也许你没有将 Jedis 对象返回到池中,并且你的 redis-server 有连接限制。

        每个工作线程都应该在其工作完成后将 Jedis 实例返回到池中:

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

        【讨论】:

        • 是的@Jarek,我已经返回资源了。 pool.returnResource(绝地武士); pool.destroy();
        • 在我的 Java 应用程序中,我使用 Jedis2.0.0.jar 文件,redis 服务器版本为 2.4.13。是不是有问题?
        • returnResource 是受保护的方法,您不能使用它。你需要使用资源try (Jedis jedis = pool.getResource()) {}
        【解决方案7】:

        当 jedis 无法访问所需的 redis 实例(域/IP、端口或密码)时,我遇到了该错误,如果它们是错误的,或者它们之前是正确的,现在是错误的,或者如果它们是正确的,但防火墙阻止了对它们的访问,等等。

        我知道 OP 已确认已运行 redis-cli 来确认连接,但如果确认是从 jedis 调用来自的同一位置(可能是利用 jedis 的应用服务器连接到某个 redis 服务器)。

        但原来的帖子是 2012 年的,所以我不希望听到更新,但我把这些留给可能找到这个帖子的其他人。

        【讨论】:

          【解决方案8】:

          我费了很大劲才解决“无法从池中获取资源”错误,但我终于解决了它,希望它也能解决你的问题!

          将“application.properties”中的端口从 “6380”到“6379” 那么它应该可以正常工作!

          【讨论】:

          • 正如目前所写,您的答案尚不清楚。请edit 添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。你可以找到更多关于如何写好答案的信息in the help center
          • 简化帖子!
          【解决方案9】:

          我只想在@mrt 和@charlie 的回答中加一点。我们需要检查redis服务器的属性。 对于 redis 客户端 3.2.0 及以上版本,我们也可以设置 ssl 属性,在 JedisShardInfo 的帮助下,如下所示:

          JedisShardInfo shardInfo = new JedisShardInfo(redisServer, redisServerPort, redisTimeout, redisSsl);
          shardInfo.setPassword(redisPassword);
          Jedis jedis = new Jedis(shardInfo);
          

          并与 jedisPool:

          jedisPool = new JedisPool(poolConfig, redisServer, redisServerPort, redisTimeout, redisPassword, redisSsl);
          jedis = jedisPool.getResource();
          

          poolConfig 中,您可以指定各种属性,如setMaxIdlesetMaxWaitMillissetMaxTotal 等。

          【讨论】:

            猜你喜欢
            • 2014-03-30
            • 2015-03-02
            • 2021-01-11
            • 2018-03-18
            • 1970-01-01
            • 2014-06-08
            • 2017-09-15
            • 2019-10-27
            • 1970-01-01
            相关资源
            最近更新 更多