Read write separation of redis cluster

Keywords: Programming Redis Spring Jedis Database

Read write separation of redis cluster

1. Cluster deployment In this article, we will not elaborate on how to deploy the master-slave cluster. In general, slaveOf configuration is used for initialization configuration.

2. Integrating with springboot to realize read-write separation The call layer read-write separation is realized by annotation, and then which read library is accessed is determined according to the modular operation

  • Add redis configuration in spring cloud configuration center:

Configure read / write nodes

spring:
  redis:
    database: 0
    pool:
      max-active: 8
      max-idle: 9
      max-wait: -1
      min-idle: 0
    redis-master:
      host: 192.168.1.1
      prot: 6379
      password: 
      testOnBorrow: false
    redis-slave1:
      host: 192.168.1.2
      prot: 6379
      password:
      testOnBorrow: false
    redis-slave2:
      host: 192.168.1.3
      prot: 6379
      password:
      testOnBorrow: false
  • Add auto configuration class

As follows:

@Configuration
public class RedisConfiguration {

    @Value("${spring.redis.pool.max-idle}")
    private int maxIdle;
    @Value("${spring.redis.pool.max-active}")
    private int maxTotal;
    @Value("${spring.redis.database}")
    private int index;
    @Value("${spring.redis.pool.max-wait}")
    private long maxWaitMillis;
    

    @Bean(name = "redisMasterTemplate")
    public StringRedisTemplate redisMasterTemplate(@Value("${spring.redis-master.host}") String hostName,
            @Value("${spring.redis-master.port}") int port, @Value("${spring.redis-master.password}") String password, @Value("${spring.redis-master.testOnBorrow}") boolean testOnBorrow) {
        StringRedisTemplate temple = new StringRedisTemplate();
        temple.setConnectionFactory(
                connectionFactory(hostName, port, password, maxIdle, maxTotal, index, maxWaitMillis, testOnBorrow));

        return temple;
    }

    @Bean(name = "redisSlave1Template")
    public StringRedisTemplate redisSlave1Template(@Value("${spring.redis-slave1.host}") String hostName,
            @Value("${spring.redis-slave1.port}") int port, @Value("${spring.redis-slave1.password}") String password, @Value("${spring.redis-slave1.testOnBorrow}") boolean testOnBorrow) {
        StringRedisTemplate temple = new StringRedisTemplate();
        temple.setConnectionFactory(
                connectionFactory(hostName, port, password, maxIdle, maxTotal, index, maxWaitMillis, testOnBorrow));

        return temple;
    }

    @Bean(name = "redisSlave1Template")
    public List<StringRedisTemplate> redisSlaveTemplate() {
        List<StringRedisTemplate> list = new ArrayList<StringRedisTemplate>();
        list.add(redisSlave1Template());
        list.add(redisSlave2Template());
        return list;
    }

    @Bean(name = "redisSlave2Template")
    public StringRedisTemplate redisSlave1Template(@Value("${spring.redis-slave2.host}") String hostName,
            @Value("${spring.redis-slave2.port}") int port, @Value("${spring.redis-slave2.password}") String password, @Value("${spring.redis-slave2.testOnBorrow}") boolean testOnBorrow) {
        StringRedisTemplate temple = new StringRedisTemplate();
        temple.setConnectionFactory(
                connectionFactory(hostName, port, password, maxIdle, maxTotal, index, maxWaitMillis, testOnBorrow));
        return temple;
    }

    public RedisConnectionFactory connectionFactory(String hostName, int port, String password, int maxIdle,
            int maxTotal, int index, long maxWaitMillis, boolean testOnBorrow) {
        JedisConnectionFactory jedis = new JedisConnectionFactory();
        jedis.setHostName(hostName);
        jedis.setPort(port);
        if (StringUtils.isNotEmpty(password)) {
            jedis.setPassword(password);
        }
        if (index != 0) {
            jedis.setDatabase(index);
        }
        jedis.setPoolConfig(poolCofig(maxIdle, maxTotal, maxWaitMillis, testOnBorrow));
        // Initialize connection pool
        jedis.afterPropertiesSet();
        RedisConnectionFactory factory = jedis;

        return factory;
    }

    public JedisPoolConfig poolCofig(int maxIdle, int maxTotal, long maxWaitMillis, boolean testOnBorrow) {
        JedisPoolConfig poolCofig = new JedisPoolConfig();
        poolCofig.setMaxIdle(maxIdle);
        poolCofig.setMaxTotal(maxTotal);
        poolCofig.setMaxWaitMillis(maxWaitMillis);
        poolCofig.setTestOnBorrow(testOnBorrow);
        return poolCofig;
    }
}

Encapsulate call interface

@Component
public class StringRedisTemplateProxy {

	@Autowired
	private StringRedisTemplate redisMasterTemplate; 
	
	@Autowired
	private List<StringRedisTemplate> redisSlaveList; 
	
	private int index=0;
	
	public void setValue(String key,String value) {
		redisMasterTemplate.opsForValue().set(key, value);
	}
	
	public String getValue(String key) {
		index++;
		return redisSlaveList.get(index).opsForValue().get(key);
	}
}

The disadvantage here is that it is impossible to fail over. Here, virtual ip and script timing monitoring are needed. 1. Use a virtual ip to point to the redis master 2. If the slave node fails, the retry mechanism can be used to call the read node once. If the master node fails, the script needs to automatically switch a slave node to the master node and bind the virtual IP to the node.

Posted by lunarul on Tue, 10 Dec 2019 22:34:33 -0800