3

我正在运行一个使用 Jedis 访问 Redis 数据库的 Tomcat 应用程序。不时形成整个应用程序块。通过使用 JavaMelody 监控 Tomcat,我发现当对象请求 Jedis 实例时,问题似乎与 JedisPool 有关。

catalina-exec-74
java.lang.Object.wait(Native Method)
java.lang.Object.wait(Object.java:503)
org.apache.commons.pool.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:1104)
redis.clients.util.Pool.getResource(Pool.java:20)
....

这是我正在使用的 JedisPoolConfig

JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxActive(20);
poolConfig.setTestOnBorrow(true);
poolConfig.setTestOnReturn(true);
poolConfig.setMaxIdle(5);
poolConfig.setMinIdle(5);
poolConfig.setTestWhileIdle(true);
poolConfig.setNumTestsPerEvictionRun(10);
poolConfig.setTimeBetweenEvictionRunsMillis(10000);
jedisPool = new JedisPool(poolConfig, "localhost");

所以很明显,一些线程试图获取 Jedis 实例,但池是空的,无法返回实例,因此默认池行为是等待。

我已经仔细检查了我的整个代码,我很确定我将每个 Jedis 实例返回到我之前使用的池中。所以我不确定为什么我的实例用完了。

有没有办法检查池中剩下多少实例?我正在尝试为 maxActive 参数找到一个合理的值,以防止应用程序阻塞。

除了不将 Jedis 实例返回到池中之外,还有其他方法可以创建内存漏洞吗?

4

3 回答 3

4

Returning the resource to the Pool is important, so remember to do it. Otherwise when closing your app it'll wait for the resource to return.

https://groups.google.com/forum/?fromgroups=#!topic/jedis_redis/UeOhezUd1tQ

After each Jedis method call, return the resource pool. Your app has probably used all the threads and waits for some to be dropped. This may cause behavior you're explaining and the app is probably blocked.

Jedis jedis = JedisFactory.jedisPool.getResource();
try{
    jedis.set("key","val");
}finally{
    JedisFactory.jedisPool.returnResource(jedis);
}
于 2012-12-19T15:48:36.913 回答
3

部分答案希望对处于类似情况的人有所帮助,但我不确定我的问题是否与您的问题相同(如果您已经弄清楚了,请告诉我们!)。

我已经仔细检查了我的整个代码,我很确定我将每个 Jedis 实例返回到我之前使用的池中。所以我不确定为什么我的实例用完了。

我以为我必须 - 我总是把我的代码放在 try / finally 块中,但事实证明我确实有内存泄漏:

Jedis jedis = DBHelper.pool.getResource();
    try {
        // Next line causes the leak
        Jedis jedis = DBHelper.pool.getResource();
        ...
    } finally {
        DBHelper.pool.returnResource(jedis);
    }

不知道第二个电话是如何潜入的,但它确实导致了泄漏和网络应用程序的阻塞。

有没有办法检查池中剩下多少实例?我正在尝试为 maxActive 参数找到一个合理的值,以防止应用程序阻塞。

就我而言,我都发现了这个 bug,并根据 redis 服务器看到的客户端数量进行了优化。我设置了 loglevel (in redis.confto verbose(default is notice),它将每 5-10 秒报告一次连接的客户端数量。一旦我发现内存泄漏,我反复向调用该方法的页面发送请求,并观察 redis 客户端redis 报告的日志会爬升,但从未下降。我认为这将是优化的良好开端?

无论如何,希望这对某人有帮助!

于 2013-08-16T15:58:19.413 回答
0

使用 jedis pool 时,每次使用 获取资源时getResource(),都必须调用releaseResource(). 如果线程数多于资源,就会出现线程争用。我发现使用 Java ThreadLocal 为每个线程建立 Jedis 连接要简单得多。因此,对于每个线程检查 jedis 连接是否已经存在。如果是,请使用它,否则为正在运行的线程创建一个连接。这确保不会有任何锁争用或错误情况需要处理。

于 2021-07-27T12:30:12.773 回答