Redis主从原理及哨兵搭建

前言

前一段时间学习redis的主从和哨兵搭建的时候,博主真的是在部署这一块踩了一堆坑,但最终结果是好的,部署成功了。现在,就把完整原理以及生产化部署方式告诉大家,让大家在redis的学习之路上越走越远~

本文的阅前提示

  1. 可能出现的专业术语介绍:

    1. fsync:是操作系统的强制落盘指令 ,正常情况下,数据需要先暂存到缓冲区再写入磁盘,fsync可以把数据强制写入磁盘中
    2. fork:作为操作系统的一个分身术 ,主进程fork后,会复制出一个与自身一模一样的子线程,然后它会把持久化的脏活累活全交给子进程做,主线程安心接收和处理用户的请求
  2. 本文所有配置均为基于docker容器部署,需要有一定的docker部署基础

一、redis持久化配置

1. RDB持久化

1.1 什么是RDB?

RDB即redis数据备份文件,又叫做redis数据快照。当redis挂掉之后,可以利用该文件快速回复数据

1.2 触发RDB的时机

Redis内部有触发RDB的机制,在redis停机的一刻,会自动保存当前数据的快照,保存到指定文件dump.rdb文件中(ps:该文件可以自己改名,但并不建议,容易导致数据丢失);在redis服务重启的时候,redis又会重新读取rdb文件中的数据

1.3 保存RDB的形式

保存数据时,有两种形式:save和bgsave,其中,save会占用主线程进行rdb保存,bgsave会fork一个新的线程进行保存

1.4 RDB相关配置

  1. 修改触发rdb的时间与次数:save x y,即在x秒内有y个键被修改,则执行一次bgsave
  2. 压缩配置:rdbcompression yes,但是不建议开启,会对磁盘造成一定压力
  3. rdb的文件名称:dbfilename xxx.rdb
  4. 文件保存路径:dir /xxx/xxx(自定义)

1.5 RDB的bgsave的流程

  1. fork主进程得到一个子进程,共享内存空间
  2. 利用子进程读取数据从保存到rdb文件中
  3. 替换旧的rdb文件

1.6 RDB的缺点

  1. RDB间隔时间长
  2. 具有数据丢失的风险

2. AOF持久化

2.1 什么是AOF

AOF全称数据追加文件

它不会把数据直接进行保存在文件中,而是会把执行过的命令保存到指定aof文件中,如图:
当redis重启恢复数据的时候,就会读取aof文件中的命令并依次执行,进而达到恢复数据的目的

2.2 相关命令

开启AOF

需要修改redis.conf配置文件(docker部署的直接创建一个新的conf文件,里面写入这一段即可完成覆盖修改):

bash 复制代码
# 是否开启AOF功能,默认是no
appendonly yes
# AOF文件的名称
appendfilename "appendonly.aof"

修改AOF的频率

bash 复制代码
# 表示每执行一次写命令,立即记录到AOF文件
appendfsync always
# 写命令执行完先放入AOF缓冲区,然后表示每隔1秒将缓冲区数据写到AOF文件,是默认方案
appendfsync everysec
#写命令执行完先放入AOF缓冲区,由操作系统决定何时将缓冲区内容写回磁盘
appendfsync no

三种频率的作用:
但是,由于AOF记录的是大量的指令,而RDB记录的是二进制数据 。同时,在加载方面,RDB中的二进制数据可以一步到位,直接加载到内存中,但是,AOF中的命令却需要一条条来执行,在数据量、操作量总量较大的时候,需要的时间会成倍增加。

为了解决这个问题,AOF提供了一套解决方案:AOF文件重写

2.2 优化方法------自动重写AOF文件

因为AOF是对命令的记录,所以其实在最后一次命令执行前的大量的命令意义并不大,甚至可以说是毫无意义的。Redis会通过执行bgrewriteaof命令,对命令内容进行重写,删减大量无效命令,用最少的命令达到相同的效果

这个重写的阈值是可以自己去设置的:

2.3 RDB与AOF的对比

RDB AOF
持久化方式 对整个内存定时做快照 记录每一次执行的命令
数据完整性 不完整,两次数据备份之间存在数据丢失 相对完整,取决于刷盘策略
文件大小 会压缩,文件很小 记录命令,文件很大
宕机恢复速度 很快,直接将二进制数据写入内存 很慢,需要逐个执行命令
数据恢复优先级 较低,因为数据完整性不如AOF 高,数据完整性高
系统资源占用 高,会占用大量CPU和内存消耗 低,主要是磁盘IO,但是对命令进行重写的时候会占用大量CPU和内存消耗
使用场景 对数据完整性要求不高,追求更高的启动速度 对数据完整性要求高的场景

二、redis主从搭建及原理

3. redis主从搭建

3.1 搭建redis主从的目的

redis中的写操作较少,但是读操作较多 ,因此,可以把读操作交给从节点进行完成,需要查询数据的时候让主节点将请求转给从节点进行获取,进而提高redis的并发能力。

从节点的数据是通过主节点进行数据同步获得的

主从节点中,主节点可读可写,从节点只允许读,写会报错

3.2 搭建方式

  1. 使用命令在docker中创建几个redis实例,然后创建一个共享网络,让这些实例共享同一个docker网络。创建redis的方式:
bash 复制代码
docker run -d --name redis -p 6379:6379 -v redis-data:/data -e REDIS_PASSWORD=xxxxxx --restart=always redis:8.2.1 redis-server --requirepass xxxxxx
  1. 进入其中一个实例容器内部(docker exec -it redis /bin/bash),使用命令redis-cli进入与redis的交互界面
  2. 把该实例设置为主节点:
bash 复制代码
replicaof no one
  1. 其他几个实例采取相同的方式,但是要设置为从节点:
bash 复制代码
replicaof 主节点ip 主节点port

注意:这里的ip是内网ip,千万不要写成宿主机ip了,可以使用docker inspect xxx进行查看

4.主从同步原理

4.1 数据同步原理

通过比对主从两节点的数据集replid和偏移量offset来判断应该使用rdb进行数据全量复制的全量同步 还是使用实时的命令传播机制进行数据追加的增量同步

3个重要概念:

  1. Replication Id:简称replid,是数据集的标记,id一致则说明是同一个数据集,每个master都一个唯一的replid
  2. offset:偏移量,随着记录在repl_baklog中的数据增多而逐渐增大。slave完成同步时也会记录当前同步的offset。如果slave的offset小于master的offset,说明slave数据落后于master,需要更新。
  3. repl_backlog(复制积压缓冲区): Redis 主节点上的一个固定大小的环形缓冲区,用于暂存主节点执行bgsave命令期间执行的新命令

4.2 主从全量同步原理

即:使用rdb进行数据全量复制的全量同步

主从节点进行数据同步的时候,从节点必须向主节点声明自己的replid和offset,主节点会进行replid的对比:

  • 如果replid不一致,说明这是一个新的从节点,主节点会返回它目前的replid和offset给从节点,并进行一次全量数据同步;

  • replid一致的情况下,分两种情况:

    • 从节点的 offset 在主节点 repl_backlog 的有效覆盖范围时,会进行增量同步(4.3);
    • 从节点的 offset 不在主节点 repl_backlog 的有效覆盖范围时,会进行一次全量同步
      图示如下:
      总结:全量同步执行时机为主从第一次建立联系时以及从节点的offset不在主节点的repl_backlog的有效覆盖范围时

4.3 主从增量同步原理

即:实时的命令传播机制进行数据追加的增量同步

主要使用到的是repl_backlog

  • repl_backlog本质上是一个环形数组 ,slave和master会进行追逐,slave宕机之后,master比slave超出的部分就是master比slave多执行的命令。在slave节点恢复宕机之后,就会执行repl_backlog里面的命令进行增量同步
  • slave挂机时间过长 ,并且master在此期间执行了大量命令 ,记录量一旦超出了该数组最大容量(转满一圈) ,就会从头开始重新记录,导致之前的命令记录被覆盖,无法进行增量同步
  • 当slave检测到命令被覆盖时,就会采用全量同步进行数据恢复

4.4 主从同步优化方法(参数设置以及节点调整)

  1. 在master中配置repl-diskless-sync yes启用无磁盘复制,避免全量同步时的磁盘IO。
  2. redis单节点内存占用不要太大,避免RDB占用大量磁盘IO
  3. 适量提高repl_backlog的大小,尽可能减少RDB的次数,以增量同步为主,在主节点的conf文件中修改或添加repl_backlog_size 100mb
  4. 限制一个master上的从节点数量,如果从节点确实是太多了,可以采取主-从-从的形式,让一级从节点变成主节点,管理二级从节点

redis哨兵搭建

5. 哨兵的工作原理

5.1 介绍

哨兵,就相当于是上帝、监控,可以监视主从节点的运行,对不健康的主从节点提供一定的补救措施

5.2 作用

  1. 监控:会实时监测redis所有的主从节点的健康状态
  2. 自动故障恢复:在主节点宕机的时候,会马上扶持一个从节点作为新的主节点,即便在旧的主节点恢复好之后,主节点业依然是被那个扶持的从节点
  3. 通知:当redis集群出现故障时,会马上将故障信息发送给客户端

5.3 心跳机制

master的选举机制:

主节点突然因为某种原因挂了之后,哨兵需要在从节点中重新投票选举出一个新的主节点,这个选举是有规则的:

  1. 根据slave与master断开时间,超过指定值的将不再拥有被选举权
  2. 判断slave-privority值,越小越优先,但是为0时不参加
  3. 优先级一样,则会判断slave的offset,越大说明数据越新,优先度越高
  4. 如果offset也一样,最后就会判断id大小,哪个小选哪个

6. 哨兵的docker搭建

完整步骤:

  1. 满足:
  • 有一个共享docker网络(docker network create redis-network
  • Redis 主节点:假设容器名 redis-master,端口 6379
  • Redis 从节点 1:redis-slave1,端口 6380
  • Redis 从节点 2:redis-slave2,端口 6381
  • 哨兵节点 1:redis-sentinel1,端口 26379
  • 哨兵节点 2:redis-sentinel2,端口 26380
  • 哨兵节点 3:redis-sentinel3,端口 26381
  1. 创建哨兵配置文件(以 sentinel1.conf 为例): bash
bash 复制代码
# 哨兵端口(每个哨兵节点端口不同)
port 26379
# 守护进程模式(Docker 中建议关闭,用容器前台运行)
daemonize no
# 日志文件
logfile "/var/log/redis/sentinel1.log"
# 工作目录
dir /tmp
# 核心配置:监控主节点
# 格式:sentinel monitor <主节点名称> <主节点IP/容器名> <主节点端口> <投票数>
# 说明:mymaster 是主节点别名,redis-master 是主节点容器名(同一网络下可直接用),6379是端口,2表示至少2个哨兵同意才触发故障切换
sentinel monitor mymaster redis-master 6379 2
# 主节点无响应超时时间(毫秒),超过则判定主节点宕机
sentinel down-after-milliseconds mymaster 30000
# 故障切换超时时间
sentinel failover-timeout mymaster 180000
# 每次同步从节点的数量(避免同时同步消耗过多带宽)
sentinel parallel-syncs mymaster 1
# 密码
sentinel auth-pass mymaster 123456
# 禁止保护模式(Docker 环境建议关闭)
protected-mode no

其他两个哨兵的配置文件修改port和日志文件目录即可

  1. 创建数据卷挂载:
bash 复制代码
# 创建3个哨兵配置数据卷(也可以只创建1个卷,放入3个配置文件)
docker volume create redis-sentinel1-conf 
docker volume create redis-sentinel2-conf 
docker volume create redis-sentinel3-conf
docker volume create redis-sentinel1-log
docker volume create redis-sentinel2-log
docker volume create redis-sentinel3-log
  1. 复制conf文件到数据卷中:
bash 复制代码
# 1. 查看哨兵1配置卷的「宿主机实际路径」(复制输出的Mountpoint路径)
docker volume inspect redis-sentinel1-conf | grep Mountpoint

# 2. 把本地sentinel1.conf 复制到 上一步查到的宿主机卷路径(示例路径,替换成你的)
cp /本地/你的/sentinel1.conf /var/lib/docker/volumes/redis-sentinel1-conf/_data/sentinel.conf
# 其余两节点也照做
  1. 启动三个哨兵:
bash 复制代码
# 启动哨兵1
docker run -d \
  --name redis-sentinel1 \
  --net redis-network \
  --restart always \
  -p 26379:26379 \
  -v redis-sentinel1-conf:/etc/redis \
  -v redis-sentinel1-log:/var/log/redis \
  redis:8.2.1 \
  redis-sentinel /etc/redis/sentinel.conf

# 启动哨兵2
docker run -d \
  --name redis-sentinel2 \
  --net redis-network \
  --restart always \
  -p 26380:26380 \
  -v redis-sentinel2-conf:/etc/redis \
  -v redis-sentinel2-log:/var/log/redis \
  redis:8.2.1 \
  redis-sentinel /etc/redis/sentinel.conf

# 启动哨兵3
docker run -d \
  --name redis-sentinel3 \
  --net redis-network \
  --restart always \
  -p 26381:26381 \
  -v redis-sentinel3-conf:/etc/redis \
  -v redis-sentinel3-log:/var/log/redis \
  redis:8.2.1 \
  redis-sentinel /etc/redis/sentinel.conf
  1. 启动三个主从redis:
bash 复制代码
# 主节点
docker run -d \
  --name redis-master \
  --net redis-network \
  --restart always \
  -p 6379:6379 \
  redis:8.2.1 \
  redis-server --requirepass 123456 --repl_backlog_size 100mb --protected-mode no

# 从节点1
docker run -d \
  --name redis-slave1 \
  --net redis-network \
  --restart always \
  -p 6380:6380 \
  redis:8.2.1 \
  redis-server --replicaof redis-master 6379 --masterauth 123456 --protected-mode no

# 从节点2
docker run -d \
  --name redis-slave2 \
  --net redis-network \
  --restart always \
  -p 6381:6381 \
  redis:8.2.1 \
  redis-server --replicaof redis-master 6379 --masterauth 123456 --protected-mode no

结尾

以上就是redis主从原理及哨兵搭建的主要内容了,如果大家觉得文章有用的话,别忘了点赞 + 收藏 + 关注支持一下博主,下期再见~

相关推荐
环流_2 小时前
redis:持久化rdb
java·数据库·redis
難釋懷2 小时前
Redis通信协议-基于Socket自定义Redis的客户端
数据库·redis·缓存
环流_2 小时前
redis:AOF
数据库·redis·spring
半夜修仙3 小时前
Redis入门
数据库·redis·缓存
Mahir085 小时前
Redis 核心机制:数据过期策略与淘汰策略深度解析
数据库·redis·后端·缓存·面试
Mahir088 小时前
Redis 分布式锁与 Redisson 深度解析:从原生实现到工业级解决方案
数据库·redis·分布式·缓存·面试
看我干嘛!9 小时前
Redis安装
数据库·redis·缓存
Devin~Y10 小时前
大厂Java面试实录:Spring Boot/Cloud + Redis + Kafka + JVM + RAG(Spring AI)三轮追问(小Y翻车版)
java·jvm·spring boot·redis·spring cloud·kafka·mybatis
oddsand110 小时前
原理篇-Redis数据结构
数据库·redis·缓存