【问题标题】:Spring Redis template with Jedis connection factory , Redis standalone configuration and multi-threading带有 Jedis 连接工厂、Redis 独立配置和多线程的 Spring Redis 模板
【发布时间】:2018-07-30 11:22:30
【问题描述】:

我在多线程环境中使用 Spring Redis 模板。一个线程将数据保存到 Redis 中,另一个线程(调度程序)从中获取数据。 JedisConnectionFactory 用于redis模板。下面是获取redis连接的代码sn -p:

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;嵌套异常是 redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketException: Connection reset by peer: socket write error

以下是我的发现:

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

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

【问题讨论】:

  • 尝试将jedis工厂从spring data starter redis改成redis工厂。
  • 我认为这不会有什么不同。 JedisConnectionFactory 实现了 RedisConnectionFactory。我还尝试创建连接池并为池配置设置“maxTotal”和“maxIdle”,并在一夜之间运行 jar。但是,问题仍然存在。唯一的区别是现在异常的时间跨度增加了。

标签: multithreading spring-boot redis resttemplate jedis


【解决方案1】:

这个问题的原因是:

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;
}

【讨论】:

  • 我不太确定 Redis 模板是线程安全的,但只有在它使用连接池时才可以。如果未使用连接池,则同时连接调用结果... 我已经检查了 JedisConnectionFactory 默认使用池,因为可以使用 getUsePool 方法检查它(返回 true)并使用检查池配置getPoolConfig 方法为您提供 maxTotal=8maxIdle=8minIdle=0
  • 是的,JedisConnectionFactory 默认使用池,但同时连接数(多线程环境)默认为 8,对于重负载应用程序,这些默认配置无法有效工作。
猜你喜欢
  • 1970-01-01
  • 2015-10-13
  • 1970-01-01
  • 1970-01-01
  • 2020-07-27
  • 2021-10-22
  • 2018-07-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多