Vincent Devillers
Vincent Devillers

Reputation: 1628

How can I configure a Redis instance on Cloudfoundry in slave mode?

I'm trying to configure a master/slave replication on Cloudfoundry but I always fall with a 'ERR unknown command 'SLAVEOF''. I'm using Jedis as the underlying client of spring-data-reids with this code:

@Configuration
@ComponentScan(basePackages = { Constants.REDIS_PACKAGE })
@Order(1)
public class KeyValueConfig {

    @Inject
    @Named("redisMasterConnectionFactory")
    private RedisConnectionFactory redisMasterConnectionFactory;

    @Inject
    @Named("redisSlaveConnectionFactory")
    private RedisConnectionFactory redisSlaveConnectionFactory;

    @Inject
    @Named("redisCacheConnectionFactory")
    private RedisConnectionFactory redisCacheConnectionFactory;

    @Bean
    public StringRedisTemplate redisMasterTemplate() {
        StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(
                redisMasterConnectionFactory);
        HealthChecks.register(new RedisHealthCheck(stringRedisTemplate,
                "master"));
        return stringRedisTemplate;
    }

    @Bean
    public StringRedisTemplate redisSlaveTemplate() {
        StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(
                redisSlaveConnectionFactory);
        HealthChecks
                .register(new RedisHealthCheck(stringRedisTemplate, "slave"));
        return stringRedisTemplate;
    }

    @Bean
    public StringRedisTemplate redisCacheTemplate() {
        StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(
                redisCacheConnectionFactory);
        HealthChecks
                .register(new RedisHealthCheck(stringRedisTemplate, "cache"));
        return stringRedisTemplate;
    }

    /**
     * Properties to support the local and test mode of operation.
     */
    @Configuration
    @Profile({ Profiles.LOCAL, Profiles.PROD, Profiles.TEST })
    static class Default implements MasterSlaveConfig {

        @Inject
        private Environment environment;

        @Bean
        public RedisConnectionFactory redisMasterConnectionFactory() {
            JedisConnectionFactory redis = new JedisConnectionFactory();
            redis.setHostName(environment.getProperty("redis.master.hostname"));
            redis.setPort(environment.getProperty("redis.master.port",
                    Integer.class));
            redis.setPassword(environment.getProperty("redis.master.password"));
            redis.setUsePool(true);
            return redis;
        }

        @Bean
        public RedisConnectionFactory redisSlaveConnectionFactory() {
            JedisConnectionFactory redis = new JedisConnectionFactory();
            redis.setHostName(environment.getProperty("redis.slave.hostname"));
            redis.setPort(environment.getProperty("redis.slave.port",
                    Integer.class));
            redis.setPassword(environment.getProperty("redis.slave.password"));
            redis.setUsePool(true);
            return redis;
        }

        @Bean
        public RedisConnectionFactory redisCacheConnectionFactory()
                throws Exception {
            JedisConnectionFactory redis = new JedisConnectionFactory();
            redis.setHostName(environment.getProperty("redis.cache.hostname"));
            redis.setPort(environment.getProperty("redis.cache.port",
                    Integer.class));
            redis.setPassword(environment.getProperty("redis.cache.password"));
            redis.setUsePool(true);
            return redis;
        }
    }

    /**
     * Properties to support the cloud mode of operation.
     */
    @Configuration
    @Profile(Profiles.CLOUDFOUNDRY)
    static class Cloud implements MasterSlaveConfig {

        @Bean
        public RedisConnectionFactory redisMasterConnectionFactory()
                throws Exception {
            CloudPoolConfiguration cloudPoolConfiguration = new CloudPoolConfiguration();
            cloudPoolConfiguration.setPoolSize("3-5");

            CloudRedisConnectionFactoryBean factory = new CloudRedisConnectionFactoryBean();
            factory.setCloudPoolConfiguration(cloudPoolConfiguration);
            factory.setServiceName("redis-master");
            factory.afterPropertiesSet();

            return factory.getObject();
        }

        @Bean
        public RedisConnectionFactory redisSlaveConnectionFactory()
                throws Exception {
            CloudPoolConfiguration cloudPoolConfiguration = new CloudPoolConfiguration();
            cloudPoolConfiguration.setPoolSize("3-5");

            CloudRedisConnectionFactoryBean factory = new CloudRedisConnectionFactoryBean();
            factory.setCloudPoolConfiguration(cloudPoolConfiguration);
            factory.setServiceName("redis-slave");
            factory.afterPropertiesSet();

            RedisConnectionFactory redisSlaveConnectionFactory = initSlaveOnMaster(factory);

            return redisSlaveConnectionFactory;
        }

        private RedisConnectionFactory initSlaveOnMaster(
                CloudRedisConnectionFactoryBean factory) throws Exception {
            RedisConnectionFactory redisSlaveConnectionFactory = factory
                    .getObject();

            RedisServiceInfo serviceInfo = new CloudEnvironment()
                    .getServiceInfo("redis-master", RedisServiceInfo.class);

            Jedis jedis = (Jedis) redisSlaveConnectionFactory.getConnection()
                    .getNativeConnection();
            jedis.slaveof(serviceInfo.getHost(), serviceInfo.getPort());
            return redisSlaveConnectionFactory;
        }

        @Bean
        public RedisConnectionFactory redisCacheConnectionFactory()
                throws Exception {
            CloudPoolConfiguration cloudPoolConfiguration = new CloudPoolConfiguration();
            cloudPoolConfiguration.setPoolSize("3-5");

            CloudRedisConnectionFactoryBean factory = new CloudRedisConnectionFactoryBean();
            factory.setCloudPoolConfiguration(cloudPoolConfiguration);
            factory.setServiceName("redis-cache");
            factory.afterPropertiesSet();

            return factory.getObject();
        }
    }

    interface MasterSlaveConfig {

        RedisConnectionFactory redisMasterConnectionFactory() throws Exception;

        RedisConnectionFactory redisSlaveConnectionFactory() throws Exception;

        RedisConnectionFactory redisCacheConnectionFactory() throws Exception;
    }

}

Upvotes: 0

Views: 729

Answers (1)

Vincent Devillers
Vincent Devillers

Reputation: 1628

Ok... After checking the code, I found this:

rename-command SLAVEOF "" in redis.conf.erb (https://github.com/cloudfoundry/vcap-services/blob/master/redis/resources/redis.conf.erb)

So the SLAVEOF command is disable on Cloudfoudry, and so:

  • MONITOR
  • BGSAVE
  • BGREWRITEAOF
  • SLAVEOF
  • DEBUG
  • SYNC

Upvotes: 1

Related Questions