Spring 带有 Jedis 连接工厂的 Redis 模板,Redis 独立配置和多线程
Spring Redis template with Jedis connection factory , Redis standalone configuration and multi-threading
我在多线程环境中使用 Spring Redis 模板。一个线程将数据保存到 Redis 中,另一个线程(调度程序)从中获取数据。 JedisConnectionFactory 在 redis 模板中使用。下面是获取redis连接的代码片段:
JedisConnectionFactory jedisConnectionFactory() {
JedisConnectionFactory jedisConnectionFactory = null;
try {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(hostName,
port);
jedisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration);
} catch (RedisConnectionFailureException e) {
LOGGER.error("Connection break with redis " + e.getMessage());
}
return jedisConnectionFactory;
}
/**
* Redis template.
*
* @return the redis template
*/
@Bean
public RedisTemplate<String, Object> redisTemplate() {
final RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(jedisConnectionFactory());
template.setValueSerializer(new GenericToStringSerializer<Object>(Object.class));
template.setEnableTransactionSupport(true);
return template;
}
redis模板的实例是使用构造函数自动装配得到的,如下:
@Autowired
public A(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
我在使用 Redis 模板的 "findAll()" 方法从 Redis 获取数据时出现异常:
org.springframework.data.redis.RedisConnectionFailureException: java.net.SocketException: Connection reset by peer: socket write error; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketException: Connection reset by peer: socket write error
以下是我的发现:
- 当 TCP 套接字 "closing" 并且您的代码尚未收到通知时,会发生对等异常连接重置。 (findAll 的线程还没有收到关闭连接的通知)。
- Redis 模板是线程安全的(仅当使用连接池时)并自行处理连接管理。当线程将数据保存到redis并关闭连接时,可能会发生这种情况,仅在此期间,会发生获取操作并需要数据。在这种情况下,服务器可能已发出 RST 命令,但提取操作可能尚未获得它。
- 可以使用Jedis池配置;但是这里有一些贬值的方法,以后可能会导致升级问题。
请建议使用 "JedisConnectionFactory"、"RedisStandAloneConfiguration" 和 "RedisTemplate" 处理多线程的最佳方法。
这个问题的原因是:
Redis 模板是线程安全的,但仅当它使用连接池时;如果未使用连接池,则同时连接调用会导致来自(服务器/客户端)任一端的 RST 信号,因此会引发 'connection reset by peer' 异常。所以,如果我们需要使用 Redis 模板,那么创建一个连接池并为池配置设置 'maxIdle' 和 'maxTotal'。另外,请确保系统在任何情况下都不应停机(休眠)。
正确运行的代码:
@Bean
JedisConnectionFactory jedisConnectionFactory() {
JedisConnectionFactory jedisConnectionFactory = null;
try {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(hostName,
port);
jedisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration);
jedisConnectionFactory.getPoolConfig().setMaxTotal(50);
jedisConnectionFactory.getPoolConfig().setMaxIdle(50);
} catch (RedisConnectionFailureException e) {
e.getMessage();
}
return jedisConnectionFactory;
}
@Bean
public RedisTemplate<String, Object> redisTemplate() {
final RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(jedisConnectionFactory());
template.setValueSerializer(new GenericToStringSerializer<Object>(Object.class));
template.setEnableTransactionSupport(true);
return template;
}
我在多线程环境中使用 Spring Redis 模板。一个线程将数据保存到 Redis 中,另一个线程(调度程序)从中获取数据。 JedisConnectionFactory 在 redis 模板中使用。下面是获取redis连接的代码片段:
JedisConnectionFactory jedisConnectionFactory() {
JedisConnectionFactory jedisConnectionFactory = null;
try {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(hostName,
port);
jedisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration);
} catch (RedisConnectionFailureException e) {
LOGGER.error("Connection break with redis " + e.getMessage());
}
return jedisConnectionFactory;
}
/**
* Redis template.
*
* @return the redis template
*/
@Bean
public RedisTemplate<String, Object> redisTemplate() {
final RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(jedisConnectionFactory());
template.setValueSerializer(new GenericToStringSerializer<Object>(Object.class));
template.setEnableTransactionSupport(true);
return template;
}
redis模板的实例是使用构造函数自动装配得到的,如下:
@Autowired
public A(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
我在使用 Redis 模板的 "findAll()" 方法从 Redis 获取数据时出现异常:
org.springframework.data.redis.RedisConnectionFailureException: java.net.SocketException: Connection reset by peer: socket write error; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketException: Connection reset by peer: socket write error
以下是我的发现:
- 当 TCP 套接字 "closing" 并且您的代码尚未收到通知时,会发生对等异常连接重置。 (findAll 的线程还没有收到关闭连接的通知)。
- Redis 模板是线程安全的(仅当使用连接池时)并自行处理连接管理。当线程将数据保存到redis并关闭连接时,可能会发生这种情况,仅在此期间,会发生获取操作并需要数据。在这种情况下,服务器可能已发出 RST 命令,但提取操作可能尚未获得它。
- 可以使用Jedis池配置;但是这里有一些贬值的方法,以后可能会导致升级问题。
请建议使用 "JedisConnectionFactory"、"RedisStandAloneConfiguration" 和 "RedisTemplate" 处理多线程的最佳方法。
这个问题的原因是:
Redis 模板是线程安全的,但仅当它使用连接池时;如果未使用连接池,则同时连接调用会导致来自(服务器/客户端)任一端的 RST 信号,因此会引发 'connection reset by peer' 异常。所以,如果我们需要使用 Redis 模板,那么创建一个连接池并为池配置设置 'maxIdle' 和 'maxTotal'。另外,请确保系统在任何情况下都不应停机(休眠)。
正确运行的代码:
@Bean
JedisConnectionFactory jedisConnectionFactory() {
JedisConnectionFactory jedisConnectionFactory = null;
try {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(hostName,
port);
jedisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration);
jedisConnectionFactory.getPoolConfig().setMaxTotal(50);
jedisConnectionFactory.getPoolConfig().setMaxIdle(50);
} catch (RedisConnectionFailureException e) {
e.getMessage();
}
return jedisConnectionFactory;
}
@Bean
public RedisTemplate<String, Object> redisTemplate() {
final RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(jedisConnectionFactory());
template.setValueSerializer(new GenericToStringSerializer<Object>(Object.class));
template.setEnableTransactionSupport(true);
return template;
}