说明:记录Redis主从结构集群搭建,伪集群示例 ,所有的Redis节点都在一个虚拟机上,所以采用不同端口号的形式,使用不同的配置文件
集群结构如下:
0、安装Redis
下载Redis:https://redis.io/download/
将下载的 redis-6.2.6.tar.gz 压缩包,上传到Linux,解压缩,假设上传到/opt/app目录下
[root@56 app]# tar -zxvf redis-6.2.6.tar.gz
检查是否安装了 gcc编译环境,如果没有安装,使用yum安装
# 检查是否安装了gcc
[root@56 redis-6.2.6]# gcc -v
# 如果没有安装,使用yum安装
[root@56 redis-6.2.6]# gcc yum install gcc
编译Redis
[root@56 redis-6.2.6]# cd /opt/app/redis-6.2.6
[root@56 redis-6.2.6]# make
之后,redis的脚本,会生成在此目录下:/opt/app/redis-6.2.6/src
1、配置文件
将Redis配置文件复制为三份,命名分别为:conf6379.conf、conf6380.conf、conf6381.conf
修改以下配置,将每个节点的配置文件,以下配置中的所有的6379,替换为此节点的端口号(如果集群不在一个机器上则忽略),这样做是为了不让生成的RDB等数据文件名字冲突和端口冲突。
修改配置文件中的以下配置:
# 将bind这一行注释掉,或者修改为0:0:0:0,这表示任意地址都可以连接此Redis服务
# bind 127.0.0.1
# 关闭保护模式,如果开启的话,外部客户端就连不上Redis
protected-mode no
# 配置redis的端口号,不同节点使用不同的端口号
port 6379
# 以守护进程运行(后台运行redis)
daemonize yes
# 服务启动后记录线程号的文件(不同节点,将下面的6379替换为此节点的端口号,防止冲突)
pidfile "/var/run/redis_6379.pid"
# 日志文件名字 (不同节点,将下面的6379替换为此节点的端口号,防止冲突)
logfile "log6379.log"
# 数据库的个数
databases 16
# 设置数据保存到数据文件中的save规则,3600秒内修改1次key,进行一次磁盘保存操作
save 3600 1
save 300 100
save 60 10000
# 指定存储至本地数据库时是否压缩数据,默认是yes,redis采用LZF压缩,需要消耗CPU资源
rdbcompression yes
# 保存rdb文件时,是否对rdb文件进行校验
rdbchecksum yes
# 保存数据的文件名字 (不同节点,将下面的6379替换为此节点的端口号,防止冲突)
dbfilename "dump6379.rdb"
# 保存数据的目录,这个目录需要提前创建出来(不同节点,将下面的6379替换为此节点的端口号,防止冲突)
dir "/opt/apps/redis/data6379"
# 是否开启aof持久化
appendonly yes
# aof文件名字 (不同节点,将下面的6379替换为此节点的端口号,防止冲突)
appendfilename "appendonly6379.aof"
# 集群配置文件,自动生成,不能人为维护 (不同节点,将下面的6379替换为此节点的端口号,防止冲突)
cluster-config-file "nodes-6379.conf"
再将次配置复制两份,作为节点6380、6381的配置文件
2、配置集群
启动redis服务
./redis-server conf6379.conf
./redis-server conf6380.conf
./redis-server conf6381.conf
启动之后,查询redis进程:
将6380、6381作为6379的从节点:
# 配置6380作为6379的从节点
[root@localhost redis]# ./redis-cli -p 6380
127.0.0.1:6380> slaveof 127.0.0.1 6379
# 配置6381作为6379的从节点
[root@localhost redis]# ./redis-cli -p 6381
127.0.0.1:6381> slaveof 127.0.0.1 6379
然后在主节点或者从节点上执行info replication
命令可以查看状态,出现以下信息即表示成功:
主节点查看:
从节点查看:
主从断连:
让从节点与主节点断开连接,如果断开连接,此时,从节点已变为独立节点,当前从节点的数据和主节点的数据是一模一样的。
# 在从节点上执行
127.0.0.1:6380> slaveof no one
OK
3、搭建哨兵(Sentinel)节点
创建一个哨兵配置文件 sentinel.conf ,加入以下内容
# redis哨兵配置文件
# 配置监听的主节点,sentinel monitor代表监控,myredis代表服务名称(可以自定义)
# 192.168.2.56 6379 分别是主节点的IP和端口,
# 注意如果哨兵和主节点在一台服务器上,这里IP不能使用127.0.0.1,而是要用 192.168.2.56的这种
# 1代表有一个或一个以上哨兵认为主节点不可用时,进行选举操作
sentinel monitor myredis 192.168.2.56 6379 1
# 关闭保护模式,只有关闭之后,才能远程连接
protected-mode no
# 哨兵端口
port 26379
# 哨兵数据存放位置
dir "/opt/app/redis-6.2.6/sentinel-data-26379"
# 日志文件
logfile "../sentinel-data-26379/log-sentinel-26379.log"
# 以守护进程运行
daemonize yes
# 进程ID保存位置
pidfile "/var/run/sentinel-data-26379.pid"
注意这里有一个坑:
在上面的哨兵配置文件 sentinel.conf 里面配置 master 节点IP时,不要使用127.0.0.1,要用具体的IP(192.168.2.56这种),如果使用前一种,使用Java客户端连接,从 JedisSentinelPool 获取 Jedis jedis = sentinelPool.getResource(); 会报出以下异常:
redis.clients.jedis.exceptions.JedisConnectionException: Failed to connect to any host resolved for DNS name.
启动哨兵:
./redis-sentinel sentinel.conf
查看进程,结果如下:
[root@localhost redis]# ps -ef|grep redis
root 2314 1 0 20:56 ? 00:00:06 ../bin/redis-server *:6379
root 2461 1 0 21:01 ? 00:00:05 ../bin/redis-server *:6380
root 2468 1 0 21:01 ? 00:00:05 ../bin/redis-server *:6381
root 3023 1 0 21:23 ? 00:00:05 ../bin/redis-sentinel *:26379 [sentinel]
root 3061 1399 0 22:16 pts/0 00:00:00 grep --color=auto redis
此时,如果 6379 主节点挂了,哨兵节点会选择新的主节点。
测试:将主节点shutdown,稍等几秒,哨兵会在从节点中重新选择新的主节点:
原主节点:
哨兵 :
新主节点:
redis6381 节点被选为新的主节点,如果redis6379再次连接上,那他也是redis6381的从节点;
4、Java客户端连接
单机Redis,Java客户端配置
新建一个maven项目,在pom文件中,引入jedis依赖:
redis.clients
jedis
4.1.1
建一个类测试:
public class Test {
public static void main(String[] args) {
Jedis jedis = new Jedis("192.168.2.56", 6379);
String a = jedis.set("a", "1");
System.out.println(a);
System.out.println(jedis.get("a"));
jedis.close();
}
}
Redis主从复制+哨兵模式,Java客户端的配置
仍然是在pom文件中,引入jedis依赖:
redis.clients
jedis
4.1.1
这种模式,只需要配置所有哨兵的IP和端口,放在Set集合内,新建一个类测试:
public class Test {
public static void main(String[] args) {
// 哨兵节点
HashSet sentinelSet = new HashSet<>();
sentinelSet.add("192.168.2.56:26379");
// 创建pool
JedisSentinelPool sentinelPool = new JedisSentinelPool("myredis", sentinelSet);
System.out.printf("当前Master节点:%s%n", sentinelPool.getCurrentHostMaster());
// 从pool中,获取一个jedis对象,操作redis
Jedis jedis = sentinelPool.getResource();
System.out.printf("设置值:%s%n", jedis.set("a", "1"));
System.out.printf("获取值:%s%n", jedis.get("a"));
// 释放jedis到pool中
sentinelPool.returnResource(jedis);
// 释放pool
sentinelPool.close();
}
}
SpringBoot项目中,集成Redis
新建一个SpringBoot项目,pom文件中,加入以下依赖:
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-data-redis
2.6.4
org.springframework.boot
spring-boot-test
2.6.5
compile
org.springframework.boot
spring-boot-starter-test
RELEASE
compile
com.alibaba
fastjson
1.2.79
在配置文件 application.properties 中,加入此 Redis哨兵的配置:
#哨兵节点IP和端口,多个之间用英文逗号分割
spring.redis.sentinel.nodes=191.168.2.56:26379
spring.redis.sentinel.master=myredis
创建一个java类,配置 RedisTemplate 的序列化方式:
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate redisTemplate = new RedisTemplate();
redisTemplate.setConnectionFactory(redisConnectionFactory);
Jackson2JsonRedisSerializer
此时,Redis已经配置好了,如果要使用Redis,在对应的地方,注入 RedisTemplate 即可。
创建一个测试类:
// RedisBootApplication是启动类名字
@SpringBootTest(classes = RedisBootApplication.class)
class TestSer {
@Autowired
RedisTemplate redisTemplate;
@Test
void getString() {
redisTemplate.opsForValue().set("a", 100);
Object a = redisTemplate.opsForValue().get("a");
System.out.println(a);
}
}
5、问题
-
为什么哨兵的配置文件,只需要配置主节点IP和端口?
答:哨兵会从redis主节点上,获取从节点的连接信息,然后对其进行监听