有道无术,术尚可求,有术无道,止于术。
本系列Redis 版本 7.2.5
源码地址:https://gitee.com/pearl-organization/study-redis-demo
文章目录
- 1. 概述
- 2. 工作原理
- 2.1 建立连接
- 2.2 全量复制
- 2.3 命令传播
- 2.4 增量复制
- 3. 拓扑架构
- 3.1 一主一从
- 3.2 一主多从
- 4. 案例演示
- 4.1 安装
- 4.2 修改配置
- 4.3 启动
- 4.4 测试
1. 概述
官方文档
主从复制(Master-Slave Replication
)是一种常见的数据库复制技术,用于实现数据备份、读写分离和高可用。
Redis
也支持主从复制,可以将一个 Redis
服务器的数据复制到多个其他 Redis
,从服务器(Slave
)保持与主服务器(Master
)相同的数据副本。
基本概念:
- 主节点(
Master
):负责接收客户端的写操作,并将其同步到从节点。 - 从节点(
Slave
):只能接收读操作请求,不能进行写操作。从节点会复制主节点的数据,并保持与主节点的数据同步。
复制方式:
- 全量复制:主节点将所有数据发送给从节点进行复制,适用于从节点第一次复制数据或从节点数据丢失需要重新复制的情况。
- 增量复制:主节点只发送最新的修改数据给从节点进行复制,适用于从节点已经复制过数据,只需要同步最新数据的情况。
使用场景:
- 读写分离:主节点提供写服务,由从节点提供读服务。在写少读多的场景下,通过多个从节点分担读负载,可以大大提高并发能力。
- 数据备份与恢复:通过主从复制,可以将主服务器的数据实时复制到从服务器,以实现数据的备份和灾难恢复
- 高可用基石:主从复制是哨兵模式和集群模式能够实施的基础。
2. 工作原理
Redis
主从复制大致可以分为以下三个阶段:
- 建立连接
- 全量复制
- 命令传播
- 增量复制
序列图如下:
2.1 建立连接
当从节点初次启动时,需要和主节点建立连接,为数据同步做好准备。
在下面的演示中,使用了 replicaof
配置了主节点 IP
、端口,从节点会根据地址建立 Socket
连接。建立成功后,节点会发送 Ping
命令,以检测连接是否可用。
如果主节点配置了密码认证,从节点还需要配置 masterauth
参数,通过向主节点发送 auth
命令进行认证认证。
建立连接后,Redis
使用心跳机制来监视主从复制中的各个节点的健康状态。主节点会定期向其所有从节点发送 PING
命令,从节点在收到 PING
命令后,会向主节点回复一个 PONG
响应。如果从节点长时间未能响应心跳,主节点可能会将其标记为下线,并尝试重新连接或者执行故障转移。
可以通过设置 repl_ping_replica_period
参数来设置心跳间隔,默认值为 10
秒:
repl-ping-replica-period 10
2.2 全量复制
第一次连接到主节点时,从节点会发送 psync
进行全量复制。主节点收到命令后,执行 bgsave
命令,后台生成 RDB
文件,并在复制缓冲区中记录所有的写命令。
主节点将 RDB
文件和复制缓冲区中的写命令,发送给从节点进行同步、执行,完成复制的初始化。
2.3 命令传播
全量复制完成后,主节点会将执行的写命令发送给从节点,从节点接收命令并执行。
2.4 增量复制
在主从复制环境中,可能会存在因为网络中断、从节点宕机等问题,造成数据传输不完整或中断。当从节点再次连上主节点后,主节点需要补发丢失数据给从节点。
重连前丢失的部分数据,会被保存在复制积压缓冲区中,默认为 1MB
。复制积压缓冲区(repl_backlog_buffer
)是一个在主节点上维护的固定大小的先进先出(FIFO
)队列。它用于存储主节点最近执行的写命令,以便在从节点连接断开后重新连接时,能够补发从节点在断开期间错过的命令。这样,从节点就可以通过部分复制来更新自己的数据,而不是进行全量复制,从而节省时间和带宽。
每个 Redis
节点启动后都会动态分配一个 40
位的十六进制字符串作为运行 ID
,运行 ID
的主要作用是用来唯一识别 Redis
节点,可以使用 info server
命令查看:
主节点:0>info server
# Server
# 运行ID
run_id:e0004e896ede04b48ab9d7149ab7052932d32dac
主从节点会维护自身的复制偏移量 offset
,在主节点使用 info replication
命令可以查看到所有节点的偏移量:
主节点:0>info replication
# Replication
# 角色,可以是 master(主节点)或 slave(从节点)
role:master
# 从节点个数
connected_slaves:2
# 从节点的复制信息,包括 IP、端口、状态、偏移量
slave0:ip=192.168.56.102,port=6379,state=online,offset=656,lag=0
slave1:ip=192.168.56.103,port=6379,state=online,offset=656,lag=1
master_failover_state:no-failover
# 主节点的唯一标识符,用来标识当前主节点的身份
master_replid:2fefa8a05871dd44887cd4d809c8de98758508b7
master_replid2:0000000000000000000000000000000000000000
# 主节点的复制偏移量,表示主节点最后一次成功传输给从节点的数据位置
master_repl_offset:656
second_repl_offset:-1
当主节点写入命令时,会更新自身的偏移量:
最新偏移量=上次偏移量+命令的字节长度
同样,从节点在收到主节点发送的命令后,也会会更新自身的偏移量,并发送给主节点。如果偏移量不一致,则说明主从节点数据不一致。例如下图中, Slave1
因为网络原因断开连接后,偏移量会不一致:
当从节点重新连接后,发送 PSYNC
命令进行增量复制,命令的格式为:
# runId:主节点运行的id
# offset:当前从节点复制的数据偏移量
psync {runId} {offset}
主节点接收到 PSYNC
命令后,会检查并确定从节点的偏移量,然后开始将未发送的数据部分重新传输给从节点,以使其数据保持同步。
3. 拓扑架构
在部署 Redis
主从复制时,可以采用多种拓扑架构,常用的有:
- 一主一从
- 一主多从
3.1 一主一从
一主一从即只有一个主节点和一个从节点,简单易用,适用于小规模应用,单点故障风险高,无法处理主节点宕机情况。
一主一从架构用于主节点出现宕机时从节点提供故障转移支持,当应用写命令并发量较高且需要持久化时,可以只在从节点上开启 AOF,这样既保证数据安全性同时也避免了持久化对主节点的性能干扰。但是这里有一个坑,需要你注意,就是当主节点关闭持久化功能时, 如果主节点脱机要避免自动重启操作。因为主节点之前没有开启持久化功能自动重启后数据集为空,这时从节点如果继续复制主节点会导致从节点数据也被清空的情况,丧失了持久化的意义。安全的做法是在从节点上执行 slaveof no one 断开与主节点的复制关系,再重启主节点从而避免这一问题。
3.2 一主多从
一主多从即只有一个主节点和多个从节点,
一主多从架构可以实现读写分离来减轻主服务器的压力,对于读占比较大的场景,可以把读命令发送到 从节点来分担主节点压力。同时在日常开发中如果需要执行一些比较耗时的读命令,如:keys、sort等,可以在其中一台从节点上执行,防止慢查询对主节点造成阻塞从而影响线上服务的稳定性。对于写并发量较高的场景,多个从节点会导致主节点写命令的多次发送从而过度消耗网络带宽,同时也加重了主节点的负载影响服务稳定性。
4. 案例演示
一主两从需要三台服务器,部署的节点 IP
:
- 主节点:
192.168.56.101:6379
- 从节点一:
192.168.56.102:6379
- 从节点二:
192.168.56.103:6379
4.1 安装
这里使用CentOS 7
进行演示,虽然CentOS
已经全面停止更新维护,这里只是演示学习,其他Linux
安装步骤基本一致(三台服务器都需要安装 Redis
)。
首先需要安装GCC
环境,用于编译C
语言程序,输入命令检查是否已安装:
[root@localhost ~]# gcc -v
如果已安装,版本需要大于4.8.5
,未安装时输入以下命令安装GCC
:
[root@localhost ~]# yum -y install gcc-c++
GCC
安装完成后,查看版本:
下载并安装Redis 7.2.5
:
# 下载
[root@localhost ~]# wget https://download.redis.io/releases/redis-7.2.5.tar.gz
# 解压
[root@localhost ~]# tar -zxvf redis-7.2.5.tar.gz
# 安装 systemd 开发包,使用 systemd 管理Redis
[root@localhost ~]# yum -y install systemd-devel
# 编译,USE_SYSTEMD=yes:构建 systemd 支持
[root@localhost ~]# cd redis-7.2.5
[root@localhost ~]# make USE_SYSTEMD=yes
# 安装
[root@localhost ~]# make install
# 切换至命令目录
[root@localhost ~]#cd /usr/local/bin/
[root@localhost ~]#ll
默认安装在 /usr/local/bin/
位置:
4.2 修改配置
接下来需要修改所有节点的配置文件,首先从源码中将 Redis
配置文件复制到配置目录:
[root@localhost /]# mkdir /etc/redis
[root@localhost /]# cp ~/redis-7.2.5/redis.conf /etc/redis/
[root@localhost bin]# vim redis.conf
三个节点都需要修改的配置:
# 允许后台启动
daemonize yes
# 关闭保护模式
protected-mode no
# 允许本机以外的地址访问
# bind 127.0.0.1
# 设置密码
requirepass 123456
两个从节点需要单独添加的复制配置:
# 配置主节点 IP、端口
replicaof 192.168.56.101 6379
# 主节点的认证密码
masterauth "123456"
4.3 启动
这里直接使用命令启动,首先启动主节点,再启动从节点:
./redis-server /etc/redis/redis.conf &
从节点启动日志如下:
4.4 测试
使用可视化工具,连接所有节点,在任一节点中,可以使用 info replication
命令查看节点信息:
主节点:0>info replication
"# Replication
role:master
# 从节点个数
connected_slaves:2
# 从节点信息
slave0:ip=192.168.56.102,port=6379,state=online,offset=656,lag=0
slave1:ip=192.168.56.103,port=6379,state=online,offset=656,lag=1
master_failover_state:no-failover
master_replid:2fefa8a05871dd44887cd4d809c8de98758508b7
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:656
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:656
"
在主节点中存入数据:
可以在从节点中看到,数据被自动复制过来了:
在从节点中,是不允许执行写操作的: