1
votes

I am switching from a single node Redis to a sentinel based multi-node Redis instance, and since the new instance’s VCAP structure is different and is not handled by default by Spring, I understand we need to parse the VCAP ourselves and configure the Redis bean.

Following the Spring documentation here, this is how I have adapted my Redis beans:

       public RedisConnectionFactory jedisConnectionFactory(JsonArray sentinelNodes) {
              RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration().master("mymaster");
              String hostname;
              String port;
              for (int i = 0; i < sentinelNodes.size(); i++) {
                     JsonObject sentinelNode = sentinelNodes.getJsonObject(i);
                     hostname = sentinelNode.getString("hostname");
                     port = sentinelNode.getString("port");
                     sentinelConfig.sentinel(hostname, Integer.parseInt(port));
              }
              return new JedisConnectionFactory(sentinelConfig);
       }

       @Bean
       public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory cf) {
              JsonArray sentinelNodes = environmentHandler.getSentinelNodesForRedis();
              if (sentinelNodes != null) {
                     cf = jedisConnectionFactory(sentinelNodes);
              }
              RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
              redisTemplate.setConnectionFactory(cf);
              redisTemplate.setKeySerializer(new StringRedisSerializer());
              redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
              return redisTemplate;
       }

       @SuppressWarnings("rawtypes")
       @Bean
       public CacheManager cacheManager(RedisTemplate redisTemplate) {
              return new RedisCacheManager(redisTemplate);
       }

I fetch the information for the sentinel nodes from the VCAP and pass it for creating my JedisConnectionFactory. I was able to configure the beans like this, but received an Exception on runtime, stating ‘org.springframework.data.redis.RedisConnectionFailureException: Cannot get Jedis connection; nested exception is java.lang.NullPointerException: while trying to invoke the method redis.clients.jedis.JedisShardInfo.getHost() of a null object loaded from local variable 'shardInfo' | at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.fetchJedisConnector(JedisConnectionFactory.java:204)…’. In my understanding, I configured the JedisConnectionFactory using RedisSentinelConfiguration and not JedisShardInfo, shardInfo should not have been needed for me.

On checking the newer versions of this library, I noticed that this particular code was modified as this. So I adapted to this newer version, but now the application crashes during startup with the following exception.

java.lang.NoSuchMethodError: org.springframework.util.Assert.isTrue(ZLjava/util/function/Supplier;)V | at org.springframework.data.redis.connection.RedisStandaloneConfiguration.(RedisStandaloneConfiguration.java:61) | at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.(JedisConnectionFactory.java:99) | at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.(JedisConnectionFactory.java:111)…

Following the exception took me here, but I don’t see why this exception would be caused.

Could someone be able to point to where I am going wrong or point me to examples of how these multi-node Redis sentinels can be configured through Spring Boot beans?

1
There is an open issue to add Redis Sentinel support to Spring Cloud Connectors to handle such a case: github.com/spring-cloud/spring-cloud-connectors/issues/185. Would it be possible for you to add an example of the VCAP_SERVICES for your Redis service instance to this issue? That would help us ensure that the solution covers as many types of Redis services as possible. - Scott Frederick
Thanks, @Scott. I have posted my VCAP structure to the issue. Is there an ETA for the enhancement? Also, since I have already done the parsing of this VCAP and configuration of sentinel nodes, any idea why I face the exception stated above in the RedisStandaloneConfiguration class of spring-data-redis? - Nisheeth Agarwal

1 Answers

1
votes

Calling the afterPropertiesSet() method before returning the RedisConnectionFactory seems to have done the trick for now.

(Also, have set the password for the Factory.)