Skip to content

Add SSL support for Redis Cluster using jedis [DATAREDIS-974] #1547

@spring-projects-issues

Description

@spring-projects-issues

Deep Shiv opened DATAREDIS-974 and commented

Hello,

I'm trying to connect to AWS ElastiCache Redis using Spring Data Redis + Jedis combination. [Redis Cluster enabled, so it has Cluster Config endpoint, with 3 shard - each shard has 1 primary node + 2 replica nodes ]

I'm getting Read timed out error.

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

{{}}

AWS Redis Server Version : 5.0.3 / Cluster Mode : Enabled / SSL : Enabled / Auth : Enabled ( by password )

Library -- Spring-data-redis : 2.1.6.Release / jedis : 2.9.0

Telnet works to AWS Redis all nodes and cluster config endpoint at 6379 ports.

So, no issues with Redis itself, issue with Spring Data Redis in combination with Jedis.

This is how my code looks like for Cluster 

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

 

Error Stack 

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:423)
       at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.createCluster(JedisConnectionFactory.java:393)
       at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.afterPropertiesSet(JedisConnectionFactory.java:350)
       at io.github.deepshiv126.springdataredis.example.MySpringBootApplication.main(MySpringBootApplication.java:208)
... 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

 I looked into Spring Source Code and Jedis Source Code -- My assumption its Jedis not using SSL Connection ;

JedisConnectionFactory - afterPropertiesSet() --> trying to create Cluster --> under that it's trying initializeSlotsCache, which issued AUTH command to Redis Server, with password -- This is where "Read timed out" is occuring;

JedisClusterConnectionHandler - isnt suppose to use Jedis with SSL??

!https://user-images.githubusercontent.com/12883918/56941800-ade6cc00-6acb-11e9-8671-169e4e260ef4.png|width=675,height=197!

I understand local redis - you can go inside and run auth command to get authenticate. But I guess AWS Redis may not able to do that , its needs to have SSL Connection even before it runs AUTH command - Why Jedis is not using SSL Connection ?

I found another suggestion to use JedisPool - but spring-data-redis' JedisConnectionFactory doesn't accepts JedisPool. Is there any other way to do that ?

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

Another question - other libraries use redis ssl connection as rediss:// - how to Jedis Client to use SSL connection??


Attachments:

Issue Links:

Referenced from: pull request #472, and commits ac4909f, 849091d

6 votes, 6 watchers

Metadata

Metadata

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions