具有Jedis连接工厂,Redis独立配置和多线程的Spring Redis模板

时间:2018-07-30 11:22:31

标签: multithreading spring-boot redis resttemplate jedis

我在多线程环境中使用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:对等重置连接:套接字写入错误;嵌套的异常是redis.clients.jedis.exceptions.JedisConnectionException:java.net.SocketException:对等重置连接:套接字写入错误

以下是我的发现:

    当TCP套接字要“关闭”并且尚未通知您的代码时,会发生
  1. 由对等异常重置连接的情况。 (未针对关闭的连接通知findAll的线程)。
  2. Redis模板是线程安全的(仅在使用连接池的情况下),并自行处理连接管理。可能发生的情况是,当线程将数据保存到Redis中并关闭连接时,仅在此期间发生提取操作并需要数据。在这种情况下,服务器可能发出了RST命令,但获取操作可能未获得它。
  3. 可以使用Jedis池配置;但是其中有一些折旧方法会在以后导致升级问题。

请建议使用“ JedisConnectionFactory”,“ RedisStandAloneConfiguration”和“ RedisTemplate”处理多线程的最佳方法。

1 个答案:

答案 0 :(得分:0)

此问题的原因是:

Redis模板是线程安全的,但仅当它使用连接池时;如果未使用连接池,则同时进行的连接调用将导致来自(服务器/客户端)任一端的RST信号,因此将引发“对等连接重置”异常。因此,如果我们需要使用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;
}