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.