Search code examples
javaazuresslredisazure-redis-cache

Azure Redis SSL Cluster + Lettuce Java (EDIT: lettuce version < 4.2)


I need to use Azure Redis Cluster, with password, with SSL, with pipelining support.

I was using Jedis until now but it lacks support for cluster+ssl+password+pipelining combo.

I tried lettuce (https://github.com/mp911de/lettuce/releases/tag/4.1.2.Final) and currently hit a connection issue I am not able to solve on my own.

Connecting to an Azure Redis Cluster (2 * P4) works without SSL but not with. Also I can connect to a single node with SSL but without cluster support. Problem is when combining cluster+ssl, the auth call times out (the command is sent over the wire but times out).

The cluster without SSL working code looks like this:

RedisURI redisURI = RedisURI.Builder.redis(host, 6379)
  .withPassword(password)
  .build();
RedisClusterClient client = RedisClusterClient.create(redisURI);
RedisAdvancedClusterCommands<String, String> connection = client.connect().sync();
connection.set("a", "1");
System.out.println(connection.get("a"));

Output is 1

Enabling SSL:

RedisURI redisURI = RedisURI.Builder.redis(host, 6380)
  .withPassword(password)
  .withSsl(true)
  .build();
RedisClusterClient client = RedisClusterClient.create(redisURI);
RedisAdvancedClusterCommands<String, String> connection = client.connect().sync();
connection.set("a", "1");
System.out.println(connection.get("a"));

It hangs during 1 minute and log4j logs looks like this:

2016-05-26 14:25:17,110 | TRACE | lettuce-nioEventLoop-3-1 | CommandEncoder | [/{CLIENT} -> {HOST}/{IP}:6380] Sent: *2
$4
AUTH
$44
{PASSWORD}
2016-05-26 14:26:17,134 | WARN  | main | ClusterTopologyRefresh | Cannot connect to RedisURI [host='***', port=6380]
com.lambdaworks.redis.RedisCommandTimeoutException: Command timed out
    at com.lambdaworks.redis.LettuceFutures.await(LettuceFutures.java:95)
    at com.lambdaworks.redis.LettuceFutures.awaitOrCancel(LettuceFutures.java:74)
    at com.lambdaworks.redis.AbstractRedisAsyncCommands.auth(AbstractRedisAsyncCommands.java:64)
    at com.lambdaworks.redis.cluster.RedisClusterClient.connectToNode(RedisClusterClient.java:342)
    at com.lambdaworks.redis.cluster.RedisClusterClient.connectToNode(RedisClusterClient.java:301)
    at com.lambdaworks.redis.cluster.ClusterTopologyRefresh.getConnections(ClusterTopologyRefresh.java:240)
    at com.lambdaworks.redis.cluster.ClusterTopologyRefresh.loadViews(ClusterTopologyRefresh.java:132)
    at com.lambdaworks.redis.cluster.RedisClusterClient.loadPartitions(RedisClusterClient.java:468)
    at com.lambdaworks.redis.cluster.RedisClusterClient.initializePartitions(RedisClusterClient.java:445)
    at com.lambdaworks.redis.cluster.RedisClusterClient.connectClusterImpl(RedisClusterClient.java:359)
    at com.lambdaworks.redis.cluster.RedisClusterClient.connect(RedisClusterClient.java:244)
    at com.lambdaworks.redis.cluster.RedisClusterClient.connect(RedisClusterClient.java:231)
    at com.ubikod.ermin.reach.tools.Test.main(Test.java:20)
Exception in thread "main" com.lambdaworks.redis.RedisException: Cannot retrieve initial cluster partitions from initial URIs [RedisURI [host='***', port=6380]]
    at com.lambdaworks.redis.cluster.RedisClusterClient.loadPartitions(RedisClusterClient.java:471)
    at com.lambdaworks.redis.cluster.RedisClusterClient.initializePartitions(RedisClusterClient.java:445)
    at com.lambdaworks.redis.cluster.RedisClusterClient.connectClusterImpl(RedisClusterClient.java:359)
    at com.lambdaworks.redis.cluster.RedisClusterClient.connect(RedisClusterClient.java:244)
    at com.lambdaworks.redis.cluster.RedisClusterClient.connect(RedisClusterClient.java:231)
    at com.ubikod.ermin.reach.tools.Test.main(Test.java:20)

Keeping SSL and disabling cluster works:

RedisURI redisURI = RedisURI.Builder.redis(host, 6380)
  .withPassword(password)
  .withSsl(true)
  .build();
RedisClient client = RedisClient.create(redisURI);
RedisCommands<String, String> connection = client.connect().sync();
connection.set("a", "1");
System.out.println(connection.get("a"));

So that's not just an SSL issue, its a SSL + cluster combo issue. I tried to use withStartTls, disabling peer verification, raising the timeout, any combination of those without luck.

Any idea if it's a library bug or an Azure Redis bug?


Solution

  • I inspected the wiki page of lettuce, and I noticed the issue was not caused by a library bug or an Azure Redis bug, unfortunately, just only the lettuce not support Redis Cluster with SSL, please see the content below from the subsection Connecting to Redis using String RedisURI of the wiki page.

    lettuce supports SSL only on regular Redis connections. Master resolution using Redis Sentinel or Redis Cluster are not supported since both strategies provide Redis addresses to the native port. Redis Sentinel and Redis Cluster cannot provide the SSL ports.