2

Previously, we were using Redis with cluster mode disabled via AWS ElastiCache.

Our Java code using Jedis was pointing to the primary single node endpoint, which was used for reads and writes.

We've now enabled cluster mode.

We have now changed the code to point to the configuration endpoint of the new Redis cluster however it is now throwing errors whenever receiving requests, see below:

Redis Unavailable. Continue using the Queue requestMessage instead. org.springframework.data.redis.ClusterRedirectException: Redirect: slot 2356 to [ipaddress]:6379.; nested exception is redis.clients.jedis.exceptions.JedisMovedDataException: MOVED 2356 [ipaddress]:6379

Our configuration code is as below:

    @Bean(name = "redisTemplate")
    public RedisTemplate<String, String> getRedisTemplate(JedisConnectionFactory jedisConnectionFactory) {
        RedisTemplate template = new RedisTemplate();
        template.setConnectionFactory(jedisConnectionFactory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new StringRedisSerializer());
        template.afterPropertiesSet();
        return template;
    }

    @Bean
    JedisConnectionFactory jedisConnectionFactory(Configuration config) {
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
        jedisConnectionFactory.setHostName(config.get(HOST));
        jedisConnectionFactory.setPort(config.getInt(PORT));
        jedisConnectionFactory.setUsePool(true);
        jedisConnectionFactory.setPoolConfig(createJedisPoolConfig(config));
        jedisConnectionFactory.afterPropertiesSet();
        return jedisConnectionFactory;
    }

    JedisPoolConfig createJedisPoolConfig(Config config) {
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxTotal(config.getInt(MAX, 8));
        poolConfig.setMaxIdle(config.getInt(MAXIDLE, 8));
        poolConfig.setMinIdle(config.getInt(MINIDLE, 1));
        poolConfig.setTestOnBorrow(true);
        poolConfig.setTestOnReturn(true);
        return poolConfig;
    }

Shouldn't just changing Jedis to point to the configuration endpoint be enough?

Do I need to change anything in my code?

Ermiya Eskandary
  • 15,323
  • 3
  • 31
  • 44
  • 2
    No your assumption is right, the endpoint needs changing, but the client also needs to know it is connecting to a cluster. In this case, you need to use [`JedisCluster`](https://github.com/redis/jedis#connecting-to-a-redis-cluster) for it to do discovery of the Redis nodes. You are getting `MOVED` as the Redis cluster is telling the client that the data being requested has been resharded to another node but the client is not aware that a cluster is being used, and thus that there are any other nodes and/or how to connect to them to even be able to get the data. – Ermiya Eskandary Feb 12 '22 at 16:28
  • 1
    Just add one node pointing to the AWS configuration endpoint to the set for the cluster, and Jedis will automatically discover the other nodes - then use as intended. Does that work? – Ermiya Eskandary Feb 12 '22 at 16:30
  • 1
    Also make sure you are on the latest version of Jedis if using cluster. `JedisConnectionFactory` also has a [cluster override](https://docs.spring.io/spring-data/redis/docs/current/api/org/springframework/data/redis/connection/jedis/JedisConnectionFactory.html) which you can use instead of using the pool. – Ermiya Eskandary Feb 12 '22 at 16:33
  • 1
    Hi there @ErmiyaEskandary, Thank you very much for the response. Am I correct in saying that I will just need to do the following: (1) Modify code to use JedisCluster, (2) Just reference one of the node end points to enable autodiscovery of all nodes There is no need to use configuration endpoint? Thanks for all of the guidance! – codemonkey1010 Feb 12 '22 at 16:59
  • 1
    You're welcome - you will need to do (1) however for (2), you will need to reference the configuration endpoint only, not the nodes. Jedis cluster will then auto-discover the nodes. Let me know if it works out. – Ermiya Eskandary Feb 12 '22 at 18:59
  • @ErmiyaEskandary Thanks again I think that worked fine. I have one question however. I appears as though we were using `RedisTemplate` before and it looks as though the commands we used here, for example redisTemplate.hasKey(cacheKey) and redisTemplate.opsForValue().set are not availible for jediscluster. Is there a way I can use the redistemplate in combination with jediscluster so I don't have to recode the methods we use or are there alternaive commands that can be used in place of redistemplate? I am having trouble finding any useful resources for this online. – codemonkey1010 Feb 13 '22 at 14:01
  • That's great - let me edit the Q and post an answer for future users. You can then create a new question for what you're mentioning as to keep the focus of this question narrow :) – Ermiya Eskandary Feb 13 '22 at 14:06
  • 1
    Sounds good thank @ErmiyaEskandary – codemonkey1010 Feb 13 '22 at 14:30

1 Answers1

4

Shouldn't just changing Jedis to point to the configuration endpoint be enough?

No, as the Redis client - Jedis in this instance - needs to be aware that it is connecting to a cluster and it currently isn't.

You are getting MOVED as the Redis cluster is telling the client that the data being requested has now been 'resharded' to another node. Jedis, however, is not aware that a cluster is being used, and thus that there are any other nodes and therefore, can't even connect to them to retrieve data.

Do I need to change anything in my code?

You need to use JedisCluster instead of JedisPool for the discovery of the Redis nodes to happen & make the other relative changes within the codebase.

Note that you only need to reference the configuration endpoint:

Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>();

jedisClusterNodes.add(new HostAndPort(CONFIGURATION_ENDPOINT, 6379));

try (JedisCluster jedisCluster = new JedisCluster(jedisClusterNodes)) {
// ...
}
Ermiya Eskandary
  • 15,323
  • 3
  • 31
  • 44