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?
VCAP_SERVICESfor 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