赞
踩
建议先看教程哦!!
最简单的,最常见的模式。
在主从复制中,数据库分为两类:
主数据库(master)
从数据库(slave)
其中主从复制有如下**特点
**:
主数据库
可以进行读写
操作,当读写操作导致数据变化时会自动将数据同步给从数据库从数据库
一般都是只读
的,并且接收主数据库同步过来的数据redis复制原理
redis 的复制分为两部分操作 同步
(SYNC)和 命令传播
(command propagate)
同步(SYNC)用来将从服务器的状态 更新到 和主服务器 一致。白话文解释就是从服务器主动获取 主服务器的数据。保持数据一致。具体实现是,主服务器收到SYNC命令后,生成RDB快照文件,然后发送给从服务器。
命令传播 (command propagate)用于在主服务器数据被修改后,主从不一致,为了让从服务器保持和主服务器状态一致,而做的命令传播。白话文解释就是主服务器收到客户端修改数据命令后,数据库数据发生变化,同时将命令缓存起来,然后将缓存命令发送到从服务器,从服务器通过载入缓存命令来达到主从数据一致。这就是所谓的命令传播。
为什么需要有同步和命令传播的两种复制操作: 当只有同步操作时候,那么在从服务器向主服务器发送SYNC命令时候,主服务器在生成RDB快照文件时候,仍然会收到客户端的命令修改数据状态,这部分数据如果不能传达给从服务器,那么就会出现主从数据不一致的现象。这时候就出现了命令传播,主服务器收到从服务器的SYNC命令后,生成RDB快照文件同时,将此段时间内收到的命令缓存起来,然后使用命令传播的操作发送从服务器。来达到主从数据一致。
上面介绍了redis复制的两种操作,而redis得主从复制正式基于 同步 和 命令传播 来实现得。下面两张图展示了redis复制的流程:
命名文件:
简介配置看:2.6条目录
这里配置文件过于长了,直接拉取拿过来用即可:
gitee地址:https://gitee.com/crqyue/springboot-redis-conf.git
三个服务中
6380主库必须的配置:就是如下几行做下更改即可
bind 127.0.0.1
port 6380
daemonize yes
logfile "6380.log"
# 主从复制配置
replicaof no one # 主库不是从其他实例复制数据
6381和6382从库:
bind 127.0.0.1
port 6381 # 6382就改为port 6382即可
daemonize yes
logfile "6381.log"
# 主从复制配置
replicaof 127.0.0.1 6380 # 从库复制主库的数据
注意:建议直接进入到文件存放目录再运行命令
redis-server redis6380.conf
redis-server redis6381.conf
redis-server redis6382.conf
ps -ef|grep redis|grep -v grep
填写主机IP等信息
其他两个同理
最后连接效果
这时切换到主库往下滑找到role这一行,
此效果证明主从配置搭建没问题
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.10.0</version>
</dependency>
spring: datasource: # oracle数据库连接 - 可以切换为自己的数据库 driver-class-name: oracle.jdbc.driver.OracleDriver url: jdbc:oracle:thin:@localhost:1521:orcl username: oa password: root type: com.alibaba.druid.pool.DruidDataSource redis: # 主从配置 master: host: 192.168.6.128 port: 6380 slave1: host: 192.168.6.128 port: 6381 slave2: host: 192.168.6.128 port: 6382 # redis: # redis哨兵配置 # sentinel: # master: mymaster # nodes: 192.168.6.128:6301,192.168.6.128:6302,192.168.6.128:6303 mybatis-plus: type-aliases-package: com.cy.entity
注意点:注意点:注意点:
有时可能会出现这样的问题:
解决方案:
解释一下:@Primary注解的作用
@Primary
注解用于标识 Spring 容器中的候选 bean,当存在多个相同类型的 bean 时,被标记为@Primary
的 bean 会被优先选择作为默认的 bean,除非通过@Qualifier
明确指定其他的 bean。
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; @Configuration public class RedisConfig { @Bean public RedisConnectionFactory masterConnectionFactory() { JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(); jedisConnectionFactory.setHostName("192.168.6.128"); jedisConnectionFactory.setPort(6380); return jedisConnectionFactory; } @Bean public RedisConnectionFactory slave1ConnectionFactory() { JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(); jedisConnectionFactory.setHostName("192.168.6.128"); jedisConnectionFactory.setPort(6381); return jedisConnectionFactory; } @Bean public RedisConnectionFactory slave2ConnectionFactory() { JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(); jedisConnectionFactory.setHostName("192.168.6.128"); jedisConnectionFactory.setPort(6382); return jedisConnectionFactory; } @Primary @Bean("redisTemplate") @Qualifier("master") public RedisTemplate<String, Object> masterRedisTemplate(RedisConnectionFactory masterConnectionFactory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(masterConnectionFactory); // 设置序列化等其他配置 StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // 设置序列化器 GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(); redisTemplate.setKeySerializer(stringRedisSerializer); redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer); redisTemplate.setHashKeySerializer(stringRedisSerializer); redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer); return redisTemplate; } @Bean @Qualifier("slave1") public RedisTemplate<String, Object> slave1RedisTemplate(RedisConnectionFactory slave1ConnectionFactory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(slave1ConnectionFactory); // 设置序列化等其他配置 StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // 设置序列化器 GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(); redisTemplate.setKeySerializer(stringRedisSerializer); redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer); redisTemplate.setHashKeySerializer(stringRedisSerializer); redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer); return redisTemplate; } @Bean @Qualifier("slave2") public RedisTemplate<String, Object> slave2RedisTemplate(RedisConnectionFactory slave2ConnectionFactory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(slave2ConnectionFactory); // 设置序列化等其他配置 StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // 设置序列化器 GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(); redisTemplate.setKeySerializer(stringRedisSerializer); redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer); redisTemplate.setHashKeySerializer(stringRedisSerializer); redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer); return redisTemplate; } }
该类的作用:就是对RedisTemplate类中一些读写方法的集中处理。使其在测试时可以直接通过该类来实现同样的效果。毕竟它原本的读写操作需要去点的东西太多了嘛
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.data.redis.core.*; import org.springframework.stereotype.Component; import java.util.List; import java.util.Set; @Component public class RedisUtil { @Autowired @Qualifier("master") private RedisTemplate<String, Object> masterRedisTemplate; @Autowired @Qualifier("slave1") private RedisTemplate<String, Object> slave1RedisTemplate; @Autowired @Qualifier("slave2") private RedisTemplate<String, Object> slave2RedisTemplate; // 根据业务需求选择使用哪个 RedisTemplate private RedisTemplate<String, Object> chooseRedisTemplate() { // 这里简单地选择使用 masterRedisTemplate return masterRedisTemplate; } // 字符串操作 public void set(String key, Object value) { chooseRedisTemplate().opsForValue().set(key, value); } public Object get(String key) { return chooseRedisTemplate().opsForValue().get(key); } // 哈希操作 public void hSet(String key, String field, Object value) { chooseRedisTemplate().opsForHash().put(key, field, value); } public Object hGet(String key, String field) { return chooseRedisTemplate().opsForHash().get(key, field); } // 集合操作 public void sAdd(String key, Object... values) { chooseRedisTemplate().opsForSet().add(key, values); } public Set<Object> sMembers(String key) { return chooseRedisTemplate().opsForSet().members(key); } // 列表操作 public void lPush(String key, Object value) { chooseRedisTemplate().opsForList().leftPush(key, value); } public List<Object> lRange(String key, long start, long end) { return chooseRedisTemplate().opsForList().range(key, start, end); } // 有序集合操作 public void zAdd(String key, Object value, double score) { chooseRedisTemplate().opsForZSet().add(key, value, score); } public Set<Object> zRange(String key, long start, long end) { return chooseRedisTemplate().opsForZSet().range(key, start, end); } // 其他操作... }
import com.cy.springbootredisdefault.SpringbootRedisDefaultApplication; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.redis.core.RedisTemplate; @SpringBootTest(classes = SpringbootRedisDefaultApplication.class) @Slf4j public class RedisTest { @Autowired @Qualifier("master") private RedisTemplate<String, Object> masterRedisTemplate; @Autowired @Qualifier("slave1") private RedisTemplate<String, Object> slave1RedisTemplate; @Autowired @Qualifier("slave2") private RedisTemplate<String, Object> slave2RedisTemplate; @Test public void testRedisOperations() { // 在主库添加键值对 masterRedisTemplate.opsForValue().set("testKey", "testValue"); // 从主库获取键值对 String valueFromMaster = (String) masterRedisTemplate.opsForValue().get("testKey"); System.out.println("Value from master: " + valueFromMaster); // // 在从库1添加键值对 // slave1RedisTemplate.opsForValue().set("testKey", "testValueSlave1"); // 从从库1获取键值对 String valueFromSlave1 = (String) slave1RedisTemplate.opsForValue().get("testKey"); System.out.println("Value from slave1: " + valueFromSlave1); // // 在从库2添加键值对 // slave2RedisTemplate.opsForValue().set("testKey", "testValueSlave2"); // 从从库2获取键值对 String valueFromSlave2 = (String) slave2RedisTemplate.opsForValue().get("testKey"); System.out.println("Value from slave2: " + valueFromSlave2); } }
打开redis连接工具查看主库和从库是否具有测key
或者
直接单元测试也行
至此,redis主从集群模式整合springboot基本使用收工!!
OK !!! 收尾!!!
若有误区或不能解决,私信我,远程协助你!!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。