我正在运行多个工作线程(大约 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 没有运行,这个异常就会被抛出。请注意。
根据 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
这种情况是经常发生还是偶尔发生?如果偶尔发生,您可能需要检查连接池的大小。
如果您使用
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;
}
如果你的代码是这样的:
JedisPoolConfig jedisPoolConfig = initPoolConfig();
jedisPool = new JedisPool(jedisPoolConfig, "*.*.*.*", 6379);
你可以试试这个:
JedisPoolConfig jedisPoolConfig = initPoolConfig();
jedisPool = new JedisPool(jedisPoolConfig, "*.*.*.*", 6379,10*1000);
这是因为对于Redis来说,默认的超时时间是2秒,但是程序可能在这个时间内已经运行完毕了。
不确定,但也许你没有将 Jedis 对象返回到池中,并且你的 redis-server 有连接限制。
每个工作线程在工作完成后都应该将 Jedis 实例返回到池中:
Jedis jedis = jedisPool.getResource();
try {
jedis.getClient().setTimeoutInfinite();
// your code here...
...
} finally {
jedisPool.returnResource(jedis);
}
当 jedis 根本无法到达所需的 redis 实例(域/ip、端口或密码)时,我收到了该错误,如果它们错误,或者它们之前是正确的,现在是错误的,或者如果它们是错误的,则可能会发生这种情况是正确的,但防火墙阻止了对它们的访问,等等。
我知道 OP 确认已运行 redis-cli 来确认连接,但确认这是否是从 jedis 调用来自的同一位置完成的(可能是利用 jedis 进行连接的应用程序服务器)会很有帮助到某些 Redis 服务器)。
但是原来的帖子是 2012 年的,所以我不希望听到更新,但我把这些留给其他可能找到这个帖子的人。
我花了很多功夫来解决“无法从池中获取资源”错误,但我终于解决了它,希望它也能帮助你!
更改“application.properties”中的端口 ‘6380’至‘6379’ 那么应该可以正常工作!
我只想在@mrt 和@charlie 的回答中补充一点。我们需要检查redis服务器的属性。 对于redis客户端3.2.0及以上版本,我们也可以在JedisShardInfo的帮助下设置ssl属性,如下所示:
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
中,您可以指定各种属性,例如 setMaxIdle
、setMaxWaitMillis
、setMaxTotal
等。
在 AWS Elastic Cache (Redis) 上如果
Redis AUTH default user access
是Yes
,需要像这样在JedisPool中设置SSL=true
boolaen SSL=true;
jedisPool = new JedisPool(poolConfig, redisServer, redisServerPort, redisTimeout, redisPassword, SSL);
这发生在我的应用程序中,实际上我使用的是一个被多个函数调用的对象,而这些函数不是线程安全的。
问题是对单个对象的多次调用导致调用损坏。
类似这样的事情:
Class A{
Object B;
function1(){
B.doSomething();
}
function2(){
B.doSomething();
}
}
由于它们不是线程安全的,我收到了这些错误:
redis.clients.jedis.exceptions.JedisConnectionException:java.net.SocketException:套接字已关闭
和
redis.clients.jedis.exceptions.JedisConnectionException:java.net.SocketTimeoutException:读取超时
这就是我修复它的方法:
Class A{
function1(){
Object B;
B.doSomething();
}
function2(){
Object B;
B.doSomething();
}
}
希望有帮助
如何在本地安装Redis?