Jedis异常java.net.ConnectException:地址已在使用中

时间:2015-03-31 08:04:26

标签: java redis mqtt jedis

我有一个Jedis服务器,我已经制作了一个单独的RedisManager来管理jedis连接。 RedisManager的代码如下

package RedisServerPackage;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class RedisManager {
private static final RedisManager instance = new RedisManager();
private static final JedisPoolConfig poolConfig= new JedisPoolConfig();
private static JedisPool pool = null;
private RedisManager() {}

public final static RedisManager getInstance() {

    if(pool == null)
    {
        poolConfig.setMaxTotal(-1);
        pool = new JedisPool(poolConfig,"localhost");
    }

        return instance;
    }

    public void release() {
        pool.destroy();
    }

    public Jedis getJedis() {
        return pool.getResource();
    }

    public void returnJedis(Jedis jedis) {
        pool.returnResource(jedis);
     }
}

现在我执行我的代码,我有大约1000个客户端命中服务器并使用PubSub模型执行某些操作。我监控了redis-server,发现一次最多有45个客户端处于活动状态,最大阻塞客户端大约为39个。运行客户端代码大约5分钟后,我得到异常

redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
    at redis.clients.util.Pool.getResource(Pool.java:50)
    at redis.clients.jedis.JedisPool.getResource(JedisPool.java:88)
    at RedisServerPackage.RedisManager.getJedis(RedisManager.java:31)
    at RedisServerPackage.RedisQueue.dequeue(RedisQueue.java:45)
    at RedisServerPackage.QueueProcessor.run(QueueProcessor.java:22)
    at java.lang.Thread.run(Thread.java:745)
Caused by: redis.clients.jedis.exceptions.JedisConnectionException: java.net.ConnectException: Address already in use
    at redis.clients.jedis.Connection.connect(Connection.java:148)
    at redis.clients.jedis.BinaryClient.connect(BinaryClient.java:75)
    at redis.clients.jedis.BinaryJedis.connect(BinaryJedis.java:1572)
    at redis.clients.jedis.JedisFactory.makeObject(JedisFactory.java:69)
    at org.apache.commons.pool2.impl.GenericObjectPool.create(GenericObjectPool.java:861)
    at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:435)
    at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:363)
    at redis.clients.util.Pool.getResource(Pool.java:48)
    ... 5 more
Caused by: java.net.ConnectException: Address already in use
    at java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:345)
    at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
    at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
    at java.net.Socket.connect(Socket.java:589)
    at redis.clients.jedis.Connection.connect(Connection.java:142)
    ... 12 more

我无法找出导致此异常的原因。另外,我正在重用jedis实例。示例代码是

public void JedisExample(String temporaryString) {

        Jedis jedis = manage.getJedis();

        try {

        // Some code here

        } catch (Exception e) {
            System.out.println(e);
        }finally{
            manager.returnJedis(jedis);
            // manage is an instance of RedisManager class provided before.
        }
    }

1 个答案:

答案 0 :(得分:0)

在尝试负载测试服务器应用程序时,我在MacOS上间歇性地发生了此异常。

事实证明,问题与以下事实有关:macOS只有16K端口可用,直到通过套接字TIME_WAIT才能释放。 TIME_WAIT的默认超时为15秒。

您可以通过

检查您的
sysctl net.inet.tcp.msl

为了临时修复它以便进行负载测试,我使用了

sudo sysctl -w net.inet.tcp.msl=1000

这将TIME_WAIT减少到1秒,从而允许更快地创建和释放连接,这又使我能够让Tomcat以大约4000 qps的速率将REST请求转换为Redis PUBSUB消息,并在轰炸4小时后出现0个错误16个并发的攻城线程。以前,大约有1%的请求会出错,但上述情况除外。

问题的作者没有说明操作系统,但是我希望这个答案可能对遇到类似情况的其他人有所帮助,因为在Jedis中搜索此类异常时,该条目位于顶部。基本上,无论使用什么操作系统,在进行负载测试时都要检查TIME_WAIT。

更新

警告。 请勿在生产中使用它! 理想情况下,在工作站上进行负载测试后,将其增加到15秒。减少TIME_WAIT可能很危险,因为套接字在关闭后变得更快可用,并且一些延迟的数据包可能到达新打开的连接,从而导致无法预料的错误甚至损害安全性。在决定遵循上述说明或咨询网络工程师之前,请阅读有关TCP / IP和TIME_WAIT的更多信息。