主从复制(replica)
一主二从
三大命令:
- 主从复制
replicaof 主库ip port
配从不配主- 改换门庭
slaveof 新主库ip port
- 自立门户
slaveof no one
从机不能执行写命令
修改配置文件
- 关闭daemonize no (否则与docker的-d选项起冲突运行不起来)
- 注释掉bind 127.0.0.1
- protected-mode no
- 指定端口
- 指定当前工作目录,dir
- pid文件名字,pidfile
- log文件名字,logfile
- requirepass
- dump.rdb名字
- aof文件,appendfilename
- 从机访问主机的通行密码masterauth,必须(主机不需要配,从机需要配)
启动一主二从redis实例
- 创建日志文件添加权限
touch /docker-v/redis-replica/redis6379/logs/redis.log
touch /docker-v/redis-replica/redis6380/logs/redis.log
touch /docker-v/redis-replica/redis6381/logs/redis.log
chmod 777 /docker-v/redis-replica/redis6379/logs/redis.log
chmod 777 /docker-v/redis-replica/redis6380/logs/redis.log
chmod 777 /docker-v/redis-replica/redis6381/logs/redis.log
- 先开启master再启动两台slave
#----------master
docker run -p 6379:6379 --name redis6379 --privileged=true \
-v /docker-v/redis-replica/redis6379/redis.conf:/etc/redis/redis.conf \
-v /docker-v/redis-replica/redis6379/data:/data \
-v /docker-v/redis-replica/redis6379/logs:/var/log/redis \
-d redis:7.0.0 redis-server /etc/redis/redis.conf
#----------slave1
docker run -p 6380:6379 --name redis6380 --privileged=true \
-v /docker-v/redis-replica/redis6380/redis.conf:/etc/redis/redis.conf \
-v /docker-v/redis-replica/redis6380/data:/data \
-v /docker-v/redis-replica/redis6380/logs:/var/log/redis \
-d redis:7.0.0 redis-server /etc/redis/redis.conf
#----------slave2
docker run -p 6381:6379 --name redis6381 --privileged=true \
-v /docker-v/redis-replica/redis6381/redis.conf:/etc/redis/redis.conf \
-v /docker-v/redis-replica/redis6381/data:/data \
-v /docker-v/redis-replica/redis6381/logs:/var/log/redis \
-d redis:7.0.0 redis-server /etc/redis/redis.conf
主从关系查看
- 主机日志
- 从机日志
- 命令查看(info replication)
缺点
由于所有的写操作都是先在Master上操作,然后同步更新到Slave上,所以从Master同步到Slave机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave机器数量的增加也会使这个问题更加严重。
如果master挂了,默认情况下不会再slave节点中自动重选一个master,引出哨兵
哨兵(sentinel)
之前的一主两从复制,再加入三个哨兵,不存放数据,只是吹哨人
启动主从数据库查看状态,测试正常的主从复制
准备配置文件
######### sentinel62379.conf #########
bind 0.0.0.0
daemonize no
protected-mode no
port 26379
logfile "/var/log/redis/sentinel26379.log"
sentinel monitor mymaster 172.17.0.3 6379 2
sentinel auth-pass mymaster 123456
######### sentinel62380.conf #########
bind 0.0.0.0
daemonize no
protected-mode no
port 26380
logfile "/var/log/redis/sentinel26380.log"
sentinel monitor mymaster 172.17.0.3 6379 2
sentinel auth-pass mymaster 123456
######### sentinel62381.conf #########
bind 0.0.0.0
daemonize no
protected-mode no
port 26381
logfile "/var/log/redis/sentinel26381.log"
sentinel monitor mymaster 172.17.0.3 6379 2
sentinel auth-pass mymaster 123456
重点参数说明
- bind
服务监听地址,用于客户端连接,默认本机地址
- daemonize
是否以后台daemon方式运行(设置为no,否则会和docker run的-d参数冲突运行不起来)
- protected-mode
安全保护模式
- port
哨兵sentinel实例运行的端口 默认26379
- logfile
日志文件路径
- pidfile
pid文件路径
- dir
工作目录
sentinel monitor <master-name> <ip> <redis-port> <quorum>
哨兵sentinel监控的redis主节点的 ip port
quorum(/ˈkwɔːrəm/ 法定人数)表示最少有几个哨兵认可客观下线,同意故障迁移的法定票数
sentinel auth-pass <master-name> <password>
master设置了密码,连接master服务的密码
启动哨兵完成监控
docker run -p 26379:26379 --name redis-sentinel1 -v /docker-v/redis-sentinel/sentinel26379.conf:/etc/redis/sentinel26379.conf \
-v /docker-v/redis-sentinel/sentinel26379.log:/var/log/redis/sentinel26379.log \
-d redis:7.0.0 redis-sentinel /etc/redis/sentinel26379.conf
docker run -p 26380:26380 --name redis-sentinel2 -v /docker-v/redis-sentinel/sentinel26380.conf:/etc/redis/sentinel26380.conf \
-v /docker-v/redis-sentinel/sentinel26380.log:/var/log/redis/sentinel26380.log \
-d redis:7.0.0 redis-sentinel /etc/redis/sentinel26380.conf
docker run -p 26381:26381 --name redis-sentinel3 -v /docker-v/redis-sentinel/sentinel26381.conf:/etc/redis/sentinel26381.conf \
-v /docker-v/redis-sentinel/sentinel26381.log:/var/log/redis/sentinel26381.log \
-d redis:7.0.0 redis-sentinel /etc/redis/sentinel26381.conf
查看状态
使用建议
哨兵节点的数量应为多个,哨兵本身应该集群,保证高可用
哨兵节点的数量应该是奇数
各个哨兵节点的配置应一致
如果哨兵节点部署在Docker等容器里面,尤其要注意端口的正确映射
哨兵集群+主从复制,并不能保证数据零丢失
集群(cluster)
3主3从redis集群配置
本次端口号使用:
6382,6383,6384,6385,6386,6387
配置步骤
- 创建好docker挂载目录,创建日志文件并设置权限
mkdir /docker-v/redis-cluster/6382
mkdir /docker-v/redis-cluster/6383
mkdir /docker-v/redis-cluster/6384
mkdir /docker-v/redis-cluster/6385
mkdir /docker-v/redis-cluster/6386
mkdir /docker-v/redis-cluster/6387
touch /6382/cluster.log
touch /6383/cluster.log
touch /6384/cluster.log
touch /6385/cluster.log
touch /6386/cluster.log
touch /6387/cluster.log
chmod 777 cluster.log
- 编写配置文件
bind 0.0.0.0
daemonize no
protected-mode no
port 6382
logfile "/var/log/redis/cluster.log"
pidfile /data/cluster.pid
dir /data/
dbfilename dump.rdb
appendonly yes
appendfilename "appendonly.aof"
requirepass 123456
masterauth 123456
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
将配置文件复制五份,修改端口号
- 启动redis容器
docker run -p 6382:6382 --name redis6382 --hostname redis6382 --privileged=true \
-v /docker-v/redis-cluster/6382/redis.conf:/etc/redis/redis.conf \
-v /docker-v/redis-cluster/6382/data:/data \
-v /docker-v/redis-cluster/6382/logs/cluster.log:/var/log/redis/cluster.log \
-d redis:7.0.0 redis-server /etc/redis/redis.conf
复制该运行命令启动另外5台
- 通过redis-cli命令为6台机器构建集群关系
redis-cli -a 123456 --cluster create --cluster-replicas 1 172.17.0.3:6382 172.17.0.4:6383 172.17.0.5:6384 172.17.0.6:6385 172.17.0.7:6386 172.17.0.8:6387
本次每台redis的ip为容器内部ip
–cluster-replicas 1 表示为每个master创建一个slave节点
5. 以6382为切入点查看集群状态
读写测试
- 对6381新增两个key,看看效果如何
- 为什么报错
一定注意槽位的范围区间,需要路由到位
- 如何解决
防止路由失效加参数-c
- 查看某个key该属于对应的槽位值
CLUSTER KEYSLOT 键名称
主从扩容
- 新增6388,6389两个服务实例配置文件后并启动
- 将新增的6388节点(空槽号)作为master节点加入原集群
redis-cli -a 密码 --cluster add-node 自己实际IP地址:6388 自己实际IP地址:6382
- 检查集群情况
redis-cli -a 123456 --cluster check 172.17.0.3:6382
- 重新分配槽号(reshard)
命令:redis-cli -a 密码 --cluster reshard IP地址:端口号
redis-cli -a 密码 --cluster reshard 172.17.0.3:6382
- 检查集群情况
- 为主节点6387分配从节点6388
命令:redis-cli -a 密码 --cluster add-node ip:新slave端口 ip:新master端口 --cluster-slave --cluster-master-id 新主机节点ID
redis-cli -a 111111 --cluster add-node 192.168.111.174:6388 192.168.111.174:6387 --cluster-slave --cluster-master-id
4feb6a7ee0ed2b39ff86474cf4189ab2a554a40f-------这个是6387的编号,按照自己实际情况
- 检查集群状态
主从缩容
- 检查集群情况,先获得从节点6388的节点ID
redis-cli -a 密码 --cluster check 192.168.111.174:6388
- 从集群中将4号从节点6388删除
命令:redis-cli -a 密码 --cluster del-node ip:从机端口 从机6388节点ID
- 检查集群情况
redis-cli -a 111111 --cluster check 192.168.111.174:6385
检查一下发现,6388被删除了,只剩下7台机器了
- 将6387的槽号清空,重新分配,本例将清出来的槽号都给6381
redis-cli -a 111111 --cluster reshard 192.168.111.175:6381
- 检查集群状态
- 将6387删除
redis-cli -a 111111 --cluster del-node 192.168.111.174:6387 4feb6a7ee0ed2b39ff86474cf4189ab2a554a40f
- 检查集群情况,6387/6388被彻底祛除
SpringBoot集成redis连接集群
- 本地添加路由,对容器的访问通过虚拟机来路由
route -p add 172.17.0.0 mask 255.255.255.0 192.168.183.139
- 启动6台redis集群
- 修改yml
server.port=7777
spring.application.name=redis7_study
# ========================logging=====================
logging.level.root=info
logging.level.com.atguigu.redis7=info
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger- %msg%n
logging.file.name=D:/mylogs2023/redis7_study.log
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger- %msg%n
# ========================swagger=====================
spring.swagger2.enabled=true
#在springboot2.6.X结合swagger2.9.X会提示documentationPluginsBootstrapper空指针异常,
#原因是在springboot2.6.X中将SpringMVC默认路径匹配策略从AntPathMatcher更改为PathPatternParser,
# 导致出错,解决办法是matching-strategy切换回之前ant_path_matcher
spring.mvc.pathmatch.matching-strategy=ant_path_matcher
# ========================redis集群=====================
spring.redis.password=111111
# 获取失败 最大重定向次数
spring.redis.cluster.max-redirects=3
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-wait=-1ms
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0
spring.redis.cluster.nodes=192.168.111.175:6381,192.168.111.175:6382,192.168.111.172:6383,192.168.111.172:6384,192.168.111.174:6385,192.168.111.174:6386
- 测试
人为模拟,master-6381机器意外宕机,手动shutdown
SpringBoot客户端没有动态感知到RedisCluster的最新集群信息
Redis Cluster集群部署采用了3主3从拓扑结构,数据读写访问master节点, slave节点负责备份。当master宕机主从切换成功,redis手动OK,but 2个经典故障
- 原因
SpringBoot 2.X版本,Redis默认的连接池采用Lettuce
当Redis集群节点发生变化后,Letture默认是不会刷新节点拓扑
- 解决方案
刷新节点集群拓扑动态感应
- 修改yml
# ========================redis集群===================== spring.redis.password=111111 # 获取失败 最大重定向次数 spring.redis.cluster.max-redirects=3 spring.redis.lettuce.pool.max-active=8 spring.redis.lettuce.pool.max-wait=-1ms spring.redis.lettuce.pool.max-idle=8 spring.redis.lettuce.pool.min-idle=0 #支持集群拓扑动态感应刷新,自适应拓扑刷新是否使用所有可用的更新,默认false关闭 spring.redis.lettuce.cluster.refresh.adaptive=true #定时刷新 spring.redis.lettuce.cluster.refresh.period=2000 spring.redis.cluster.nodes=192.168.111.175:6381,192.168.111.175:6382,192.168.111.172:6383,192.168.111.172:6384,192.168.111.174:6385,192.168.111.174:6386