JedisConnectionException - ошибка тайм-аута чтения

Я пытаюсь подключиться к AWS ElastiCache Redis с помощью комбинации Spring Data Redis + Jedis. [Redis Cluster включен, поэтому у него есть конечная точка Cluster Config с 3 шардами - каждый шард имеет 1 первичный узел + 2 узла реплики]

Я получаю сообщение об ошибке "Время ожидания истекло".

Caused by: redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out

Версия сервера AWS Redis: 5.0.3 / Режим кластера: включен / SSL: включен / Auth: включен (по паролю)

Библиотека - Spring-data-redis: 2.1.6. Выпуск / jedis: 2.9.0

Telnet работает со всеми узлами AWS Redis и конечной точкой конфигурации кластера на 6379 портах.

Я попробовал Redisson сам по себе, он без проблем подключается к AWS Redis.

Итак, проблем с самим Redis нет, проблема с Spring Data Redis в сочетании с Jedis.

Мой код выглядит так -

        RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
        redisClusterConfiguration.setClusterNodes(listOfRedisNode);
        redisClusterConfiguration.setPassword(passwordString);


        JedisClientConfiguration.JedisClientConfigurationBuilder jedisClientConfiguration = JedisClientConfiguration.builder();
        jedisClientConfiguration.connectTimeout(Duration.ofSeconds(60));
        jedisClientConfiguration.useSsl();
        jedisClientConfiguration.usePooling();


        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(redisClusterConfiguration, jedisClientConfiguration.build() );
        jedisConnectionFactory.afterPropertiesSet();

        final RedisTemplate<String, Serializable> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(jedisConnectionFactory);
        redisTemplate.setKeySerializer(new JdkSerializationRedisSerializer());
        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        redisTemplate.afterPropertiesSet();

        System.out.println(redisTemplate.getClientList().size());

        StringRedisConnection stringRedisConnectionlettuce = new DefaultStringRedisConnection(redisTemplate.getConnectionFactory().getConnection());
        final String message2 = stringRedisConnectionlettuce.echo("Hello");
        System.out.println("Hello".equals(message2));

Ошибка тайм-аута чтения -

Exception in thread "main" java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
    at org.springframework.boot.loader.Launcher.launch(Launcher.java:87)
    at org.springframework.boot.loader.Launcher.launch(Launcher.java:50)
    at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51)
Caused by: redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out
    at redis.clients.util.RedisInputStream.ensureFill(RedisInputStream.java:202)
    at redis.clients.util.RedisInputStream.readByte(RedisInputStream.java:40)
    at redis.clients.jedis.Protocol.process(Protocol.java:151)
    at redis.clients.jedis.Protocol.read(Protocol.java:215)
    at redis.clients.jedis.Connection.readProtocolWithCheckingBroken(Connection.java:340)
    at redis.clients.jedis.Connection.getStatusCodeReply(Connection.java:239)
    at redis.clients.jedis.BinaryClient.connect(BinaryClient.java:96)
    at redis.clients.jedis.Connection.sendCommand(Connection.java:126)
    at redis.clients.jedis.Connection.sendCommand(Connection.java:117)
    at redis.clients.jedis.BinaryClient.auth(BinaryClient.java:564)
    at redis.clients.jedis.BinaryJedis.auth(BinaryJedis.java:2138)
    at redis.clients.jedis.JedisClusterConnectionHandler.initializeSlotsCache(JedisClusterConnectionHandler.java:36)
    at redis.clients.jedis.JedisClusterConnectionHandler.<init>(JedisClusterConnectionHandler.java:17)
    at redis.clients.jedis.JedisSlotBasedConnectionHandler.<init>(JedisSlotBasedConnectionHandler.java:24)
    at redis.clients.jedis.BinaryJedisCluster.<init>(BinaryJedisCluster.java:54)
    at redis.clients.jedis.JedisCluster.<init>(JedisCluster.java:93)
    at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.createCluster(JedisConnectionFactory.java:418)
    at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.createCluster(JedisConnectionFactory.java:388)
    at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.afterPropertiesSet(JedisConnectionFactory.java:345)
    at io.github.deepshiv126.springdataredis.example.MySpringBootApplication.main(MySpringBootApplication.java:306)
    ... 8 more
Caused by: java.net.SocketTimeoutException: Read timed out
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
    at java.net.SocketInputStream.read(SocketInputStream.java:171)
    at java.net.SocketInputStream.read(SocketInputStream.java:141)
    at java.net.SocketInputStream.read(SocketInputStream.java:127)
    at redis.clients.util.RedisInputStream.ensureFill(RedisInputStream.java:196)
    ... 27 more

Я изучил исходный код Spring и исходный код Jedis - мое предположение, что он не использует SSL-соединение;

JedisConnectionFactory - afterPropertiesSet () - пытается создать кластер - под этим он пытается инициализироватьSlotsCache, который выдал команду AUTH серверу Redis с паролем - здесь происходит «Истекло время чтения»;

Я понимаю локальный Redis - вы можете зайти внутрь и запустить команду auth, чтобы пройти аутентификацию. Но я предполагаю, что AWS Redis может не справиться с этим, ему необходимо иметь SSL-соединение даже до того, как он запустит команду AUTH. Почему Jedis не использует SSL-соединение?

Это еще один поток Невозможно получить джедаев соединение при использовании SSL с Redis и Spring Data Redis говорит, используйте что-то вроде JedisPool, но JedisConnectionFactory spring-data-redis не принимает JedisPool. Есть ли другой способ сделать это?

JedisPool jedisPool = new JedisPool("rediss://" + clusterConfigEndPoint + ":6379");

Другой вопрос - другие библиотеки используют ssl-соединение redis как rediss:// - как Jedis Client использовать SSL-соединение,

Любая помощь будет очень признательна!

Спасибо!


person dshiv126    schedule 30.04.2019    source источник
comment
Обновление: чуть позже я выяснил, что у Jedis не было возможности поддерживать установку кластера с SSL-соединением; В результате Spring-Data-Redis также не поддерживал его. Теперь и Jedis, и Spring Data Redis поддерживают Redis на основе кластеров с SSL. jira.spring.io/browse/DATAREDIS-974   -  person dshiv126    schedule 06.01.2020


Ответы (1)


Я столкнулся с этим довольно долго, однако с приведенной ниже конфигурацией он отлично работает с AWS ElasticCache - Redis с включенным SSL (шифрование при передаче и шифрование в состоянии покоя включено).

Ниже зависимости Maven используются как часть приложения springboot.

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!-- Latest jedis with SSL support -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.6.0</version>
        </dependency>

@Component
public class RedisConfig {

    @Bean
    public JedisConnectionFactory jedisConnectionFactory() {

        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setHostName("PrimaryEndpoint of AWS Elastic Cache Cluster");
        redisStandaloneConfiguration.setPort(6379);
        redisStandaloneConfiguration.setUsername("userName");
        
        redisStandaloneConfiguration.setPassword(new String("password").toCharArray());

        JedisClientConfigurationBuilder jedisClientConfiguration = JedisClientConfiguration.builder();
        jedisClientConfiguration.connectTimeout(Duration.ofSeconds(60));// 60s connection timeout
        jedisClientConfiguration.useSsl();
        jedisClientConfiguration.usePooling();

        JedisConnectionFactory jedisConFactory = new JedisConnectionFactory(redisStandaloneConfiguration,
                jedisClientConfiguration.build());
        jedisConFactory.afterPropertiesSet();

        return jedisConFactory;
    }

    @Bean(value = "redisTemplate")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        return redisTemplate;
    }

}
person isudarsan    schedule 09.05.2021