对于Redis:主从复制的解析

开篇介绍:

hello 大家,本篇博客我们来学习Redis中的主从复制。

前言

在 Redis 的整个生态体系中,主从复制 是绝对绕不开的核心基石 ------ 它是 Redis 解决单点故障 、实现读写分离 、支撑高并发 的基础,更是后续进阶的哨兵模式 、Redis 集群的底层依赖,没有主从复制,Redis 就无法摆脱 "单节点脆弱性" 的桎梏,无法支撑中大型业务的稳定运行。


一、开篇直击:为什么 Redis 必须要有主从复制?

在学习主从复制的任何知识点之前,我们先静下心来,思考一个最朴素、最实际的问题:如果我们在生产环境中,只部署一台 Redis 节点,会出现什么可怕的问题?

这就是分布式系统中最经典、最致命的单点问题(Single Point of Failure,简称 SPOF)

案例 1:单点宕机,业务全面瘫痪

某小型电商平台,Redis 单节点部署,用于缓存商品详情、用户购物车数据,支撑前端的商品查询、购物车操作。某天晚上,Redis 节点所在的服务器突然断电,Redis 进程直接终止,此时发生了以下一系列灾难性后果:

  1. 所有前端商品查询请求,都无法从 Redis 获取缓存,全部穿透到后端数据库;
  2. 数据库瞬间被高并发读请求打崩,连接数耗尽,无法响应任何请求;
  3. 前端页面加载失败、购物车无法操作,用户无法下单,业务全面瘫痪;
  4. 运维人员紧急重启服务器、重启 Redis,但 Redis 数据因未开启持久化(或持久化文件损坏)全部丢失,需要从数据库全量导入数据,整个恢复过程耗时 2 小时,造成巨大的业务损失和用户流失。

案例 2:单节点性能瓶颈,无法支撑高并发

某资讯类 APP,Redis 单节点部署,用于缓存文章列表、用户浏览记录,日常读并发约 1 万 QPS,运行稳定。但在某次活动期间,APP 推出热门资讯推送,读并发瞬间飙升到 5 万 QPS,此时单节点 Redis 出现以下问题:

  1. Redis CPU 占用率飙升至 100%,无法及时处理所有读请求,大量请求超时;
  2. 网络带宽被占满,Redis 响应延迟从 10ms 飙升至 500ms 以上,前端页面加载卡顿;
  3. 主节点同时处理读请求和少量写请求(比如更新文章阅读量),写请求被阻塞,导致文章阅读量无法实时更新,数据出现临时错乱;
  4. 无法通过扩容单节点解决(CPU、内存、带宽已达上限),只能紧急降级业务,关闭热门资讯推送,影响活动效果。

案例 3:数据丢失,无法恢复

某社交平台,Redis 单节点部署,用于缓存用户会话信息(登录状态),开启了 RDB 持久化,每天凌晨 3 点自动生成 RDB 快照。某天凌晨,服务器硬盘损坏,RDB 快照文件无法读取,Redis 进程重启后,所有用户会话信息全部丢失,导致所有用户被迫重新登录,用户体验极差;同时,由于会话信息没有备份,无法恢复,大量用户投诉,平台口碑受损。

主从复制的核心价值:解决单点问题,支撑高可用、高并发

从上面 3 个案例可以看出,单节点 Redis 在生产环境中完全无法使用,而 Redis 主从复制,就是为了解决这些问题而生的,它的核心价值有 3 点,缺一不可:

  1. 解决单点故障,提升可用性:主节点宕机后,从节点可以快速切换为主节点,继续提供服务,避免业务瘫痪;
  2. 实现读写分离,分担主节点压力:主节点只处理写请求(set、incr、del 等修改操作),从节点只处理读请求(get、hget 等查询操作),将高并发读流量分摊到多个从节点,突破单节点性能瓶颈;
  3. 实现数据备份,避免数据丢失:从节点是主节点的完整数据副本,主节点数据损坏 / 丢失时,从节点可以作为备份,快速恢复数据,无需从数据库全量导入。

通俗类比:用 "老师 - 助教" 模式

为了让大家更容易理解主从复制的工作模式,我用一个 "老师 - 助教" 教学场景,做一个全程类:

  • 主节点(Master)= 授课老师:核心职责是 "讲课、更新知识",对应 Redis 主节点,负责处理所有写请求,是数据的源头,所有数据修改都先在主节点完成;
  • 从节点(Slave)= 助教老师:核心职责是 "从老师那里同步知识、给学生答疑",对应 Redis 从节点,只能从主节点同步数据,不能主动修改数据(默认只读),负责处理所有读请求;
  • 知识传递 = 数据同步:知识只能从老师传递给助教,不能反过来(助教不能教老师),对应 Redis 主从复制的 "单向数据流"------ 只能从主节点同步到从节点,从节点的数据不会反向同步给主节点;
  • 学生 = 业务客户端:学生有问题,只找助教答疑(读请求找从节点),需要更新知识(比如提交作业、提问新问题),只找老师(写请求找主节点);
  • 多助教 = 多从节点:学生越多,需要的助教越多,对应业务读并发越高,需要的从节点越多,分担答疑压力(读压力)。

二、第一章:主从复制基础认知

2.1 什么是 Redis 主从复制?

Redis 主从复制,本质上是 Redis 提供的一种自动化、单向的数据同步机制,简单来说:

我们部署多台 Redis 节点,指定其中一台为 "主节点(Master)",其他所有节点为 "从节点(Slave)",主节点会自动、实时地将自身的所有数据(包括已有的历史数据、后续新增 / 修改 / 删除的数据),复制到所有从节点中,保证所有从节点的数据,和主节点的数据完全一致,形成 "一主多从" 的架构。

这里有 3 个关键词:

  • 自动化:无需人工干预,只要配置好主从关系,主节点的数据会自动同步到从节点,后续主节点的任何数据修改,都会自动同步,不用手动执行同步命令;
  • 单向:数据流只能从主节点流向从节点,从节点不能主动向主节点同步数据,也不能修改自身同步过来的数据(默认只读);
  • 完全一致:正常情况下,所有从节点的数据,和主节点的数据完全相同,主节点修改一条数据,所有从节点都会同步修改,不会出现数据不一致的情况(特殊情况除外,后续会讲)

2.2 主从节点的核心角色与分工

主从节点的角色分工非常明确,没有任何模糊地带

2.2.1 主节点(Master)的核心职责

主节点是整个主从架构的 "核心",是数据的 "源头",所有写操作都必须在主节点完成,它的核心职责有 5 点:

  1. 处理所有写请求:这是主节点最核心的职责,所有客户端发送的写命令(set、incr、del、hset、lpush 等),都必须发送到主节点,主节点执行完写命令后,再将命令同步给从节点;
  2. 发起数据同步:主节点会主动向所有已连接的从节点,同步自身的数据,包括历史数据(首次同步)和新增数据(实时同步),无需从节点主动请求;
  3. 维护主从连接:主节点会实时维护与所有从节点的 TCP 连接,通过心跳机制,检测从节点的存活状态,一旦发现从节点下线,会断开连接,待从节点重新上线后,重新建立连接并同步数据;
  4. 记录复制状态:主节点会记录所有从节点的复制状态,包括每个从节点的 IP、端口、复制偏移量(offset)、连接状态(在线 / 离线)等,通过info replication命令可以查看;
  5. 处理从节点的同步请求:从节点上线、重连后,会向主节点发送同步请求,主节点会根据从节点的状态(首次连接 / 重连),决定执行全量复制还是部分复制,响应从节点的同步请求。
2.2.2 从节点(Slave)的核心职责

从节点是主节点的 "副本",是读请求的 "处理者",默认情况下不能处理写请求,它的核心职责有 5 点,和主节点的职责一一对应:

  1. 处理所有读请求:这是从节点最核心的职责,所有客户端发送的读命令(get、hget、lrange、smembers 等),都可以发送到从节点,从节点直接返回数据,无需转发给主节点,从而分担主节点的读压力;
  2. 接收主节点的同步数据:从节点会主动连接主节点,接收主节点同步过来的所有数据(历史数据、新增数据),并将数据保存到自身的内存(和磁盘,若开启持久化)中,保证和主节点数据一致;
  3. 维护与主节点的连接:从节点会通过心跳机制,实时检测与主节点的连接状态,一旦发现主节点下线,会不断重试连接,直到主节点重新上线,或者人工干预切换主节点;
  4. 记录自身复制状态:从节点会记录自身的复制状态,包括主节点的 IP、端口、复制偏移量(offset)、主节点的复制 ID(replid)、连接状态等,通过info replication命令可以查看;
  5. (可选)作为其他从节点的主节点:在树形主从拓扑中,从节点可以同时作为 "中间层主节点",接收下层从节点的同步请求,将自身的数据同步给下层从节点,分担顶层主节点的压力(后续拓扑结构会详细讲)。

2.3 主从复制的核心规则

主从复制有 4 条核心规则,是 Redis 官方规定的,不能打破,一旦打破,就会导致主从复制失败、数据不一致等问题:

规则 1:角色数量规则(1 主 N 从,一从 1 主)
  • 一个主节点(Master),可以同时连接多个从节点(Slave),理论上没有上限,但实际生产中,建议不超过 10 个(太多会拖垮主节点),即 "1 主 N 从";
  • 一个从节点(Slave),只能有一个主节点(Master),不能同时连接多个主节点,即 "一从 1 主",不能实现 "一从多主" 的架构。
规则 2:数据流方向规则(单向,不可逆)
  • 数据流只能是 "主节点 → 从节点",不可逆,主节点的数据可以同步到从节点,但从节点的数据,无论如何都不能同步到主节点;
  • 即使从节点被修改(关闭只读模式),修改后的数据也不会同步给主节点,也不会同步给其他从节点,会导致自身数据与主节点不一致(后续会讲危害)。
规则 3:写操作权限规则(主写从读,默认)
  • 主节点:拥有全部写操作权限,可以执行任何写命令(set、incr、del 等),也可以执行读命令;
  • 从节点:默认拥有只读权限,只能执行读命令(get、hget 等),不能执行任何写命令,一旦执行写命令,会直接报错(后续会演示)。
规则 4:数据一致性规则(正常情况下,完全一致)
  • 正常情况下(主从连接正常、无网络中断、无命令错误),所有从节点的数据,和主节点的数据完全一致,主节点修改一条数据,所有从节点都会同步修改;
  • 特殊情况下(网络中断、主从连接异常、命令执行错误),可能会出现主从数据不一致,但网络恢复后,会自动同步,恢复一致(部分复制的作用)。

2.4 主从复制的历史演变

为了让大家更好地理解后续的原理(比如 PSYNC 命令),这里补充一点主从复制的历史演变,只是帮助大家理解 "为什么有 PSYNC 命令",了解即可:

  • Redis 2.8 版本之前:只有SYNC命令,用于实现主从复制,但SYNC命令只有 "全量复制" 一种模式,无论从节点是首次连接,还是网络闪断重连,都要执行全量复制,效率极低,消耗大量 CPU、内存、带宽;
  • Redis 2.8 版本及之后:引入了PSYNC命令,替代了SYNC命令,PSYNC命令支持 "全量复制" 和 "部分复制" 两种模式,首次连接执行全量复制,网络闪断重连执行部分复制,大幅提升了复制效率,减少了资源消耗;
  • 目前,所有主流 Redis 版本(5.0、6.0、7.0),都默认使用PSYNC命令,SYNC命令已被废弃,仅用于兼容旧版本 Redis(2.8 之前)。

2.5 核心术语解释

后续学习中,会频繁出现一些核心术语,这里提前统一解释:

核心术语 解释(老师 - 助教类比) 技术定义
主节点(Master) 授课老师,负责讲课、更新知识 主从复制架构中,负责处理写请求、发起数据同步的核心节点
从节点(Slave) 助教老师,负责同步知识、答疑 主从复制架构中,负责处理读请求、接收主节点同步数据的副本节点
复制 ID(replid) 老师的 "身份 ID",每个老师有唯一 ID,助教同步知识时,会记录老师的 ID 主节点的唯一标识(40 位字符串),用于标识主节点的数据版本,从节点会同步主节点的 replid
备用复制 ID(replid2) 助教之前跟随的老师的 ID,若当前老师离职,助教可以通过之前的老师 ID 找回旧知识 从节点用于保存上一个主节点的 replid,用于切主、重连时的同步验证
复制偏移量(offset) 助教的 "学习进度",比如学到了第 100 页课件,老师的 "讲课进度",比如讲到了第 100 页 主从节点用于记录数据同步进度的计数器,主节点每发送 1 字节命令,offset+1;从节点每接收 1 字节命令,offset+1,offset 一致则数据一致
全量复制 助教首次跟随老师,需要把老师所有的课件(历史知识)全部抄一遍 从节点首次连接主节点时,主节点将自身所有数据一次性发送给从节点的同步方式
部分复制 助教中途走神,漏抄了几页课件,只需要找老师补抄漏抄的几页,不用重新抄全部 主从网络闪断重连后,主节点只将从节点丢失的部分数据发送给从节点的同步方式
复制积压缓冲区 老师的 "板书缓冲区",用于保存最近讲过的几页课件,方便助教补抄 主节点上的固定长度环形队列,用于保存最近执行的写命令,供部分复制时补发数据,默认大小 1MB
心跳检测 老师每 10 分钟问一次助教 "在不在",助教每 1 分钟告诉老师 "我学到第 100 页了" 主从节点用于维护连接状态的机制,主节点发 PING,从节点回复 ACK,检测对方存活状态
读写分离 老师只负责讲课(写),助教只负责答疑(读),分工明确 主节点处理所有写请求,从节点处理所有读请求,分担主节点压力的部署模式

三、第二章:主从复制全配置实战

主从复制的配置非常简单,Redis 提供了三种配置方式

3.1 实战前提准备(CentOS/Ubuntu 通用)

在开始配置之前,我们需要完成一些前提准备工作,避免后续操作出现问题:

3.1.1 环境准备(明确版本,避免兼容问题)
  • 操作系统:CentOS 7.x/ Ubuntu 20.04(两种系统操作基本一致,差异会标注);
  • Redis 版本:Redis 5.0.14(推荐,兼容所有主流版本,避免使用 2.8 之前的旧版本);
  • 部署模式:本地多实例部署(一台机器启动多个 Redis 实例,模拟主从节点),优点是无需多台服务器,适合本地测试、学习;生产环境中,主从节点需部署在不同服务器,避免单台服务器宕机导致主从同时失效。
3.1.2 安装 Redis

如果还未安装 Redis,按照以下步骤操作,CentOS 和 Ubuntu 分别演示,避免遗漏:

(1)CentOS 7.x 安装 Redis
bash 复制代码
# 1. 安装依赖(gcc、gcc-c++,Redis编译需要)
yum install -y gcc gcc-c++

# 2. 下载Redis 5.0.14安装包(官网地址,速度快)
wget http://download.redis.io/releases/redis-5.0.14.tar.gz

# 3. 解压安装包(解压到/usr/local目录下)
tar -zxvf redis-5.0.14.tar.gz -C /usr/local/

# 4. 进入解压后的目录,编译Redis
cd /usr/local/redis-5.0.14/
make

# 5. 安装Redis(安装到/usr/local/redis目录下)
make install PREFIX=/usr/local/redis

# 6. 复制Redis配置文件(默认配置文件在解压目录的redis.conf)
cp /usr/local/redis-5.0.14/redis.conf /usr/local/redis/conf/

# 7. 配置Redis环境变量(方便全局执行redis-server、redis-cli命令)
echo "export PATH=$PATH:/usr/local/redis/bin" >> /etc/profile
source /etc/profile

# 8. 验证Redis安装成功(执行以下命令,无报错即成功)
redis-server -v  # 查看Redis版本,输出Redis server v=5.0.14 sha=00000000:0 malloc=jemalloc-5.1.0 bits=64 build=0
redis-cli -v    # 查看Redis客户端版本,输出redis-cli 5.0.14
(2)Ubuntu 20.04 安装 Redis
bash 复制代码
# 1. 更新软件源
apt update

# 2. 安装Redis(默认安装最新稳定版,若需5.0.14,可自行下载编译)
apt install -y redis-server

# 3. 验证Redis安装成功
redis-server -v  # 输出Redis server v=5.0.7 sha=00000000:0 malloc=jemalloc-5.2.1 bits=64 build=0
redis-cli -v    # 输出redis-cli 5.0.7

# 4. 查看Redis配置文件路径(Ubuntu默认路径)
ls /etc/redis/redis.conf  # 输出/etc/redis/redis.conf
3.1.3 多实例部署准备(核心:复制配置文件,修改端口)

本地多实例部署,核心是 "一个 Redis 安装包,多个配置文件,每个配置文件对应一个实例,端口不同",我们部署 2 个实例(后续可扩展为多个):

  • 主节点(Master):端口 6379,使用默认配置文件(轻微修改);
  • 从节点(Slave):端口 6380,复制默认配置文件,修改端口、守护进程等参数。

操作步骤(CentOS/Ubuntu 通用,路径根据自身系统调整):

bash 复制代码
# 1. 进入Redis配置文件目录(CentOS路径)
cd /usr/local/redis/conf/

# 若为Ubuntu,进入默认配置文件目录
# cd /etc/redis/

# 2. 复制配置文件,命名为redis-slave-6380.conf(从节点6380的配置文件)
cp redis.conf redis-slave-6380.conf

# 3. 修改从节点配置文件(redis-slave-6380.conf),核心修改5个参数
# 用vim编辑配置文件,不懂vim的同学,可使用nano编辑(nano redis-slave-6380.conf)
vim redis-slave-6380.conf

# 3.1 修改端口(默认6379,改为6380,避免端口冲突)
port 6380

# 3.2 开启后台守护进程运行(必须开启,否则终端关闭,Redis实例停止)
daemonize yes

# 3.3 修改pid文件路径(每个实例的pid文件必须不同,避免冲突)
pidfile /var/run/redis_6380.pid

# 3.4 修改日志文件路径(每个实例的日志文件分开,方便排查错误)
logfile "/var/log/redis/redis-6380.log"

# 3.5 修改数据存储路径(每个实例的数据目录分开,避免数据混淆)
dir /var/lib/redis/6380

# 4. 创建日志文件和数据目录(避免启动时报错,权限不足)
# CentOS
mkdir -p /var/log/redis/
mkdir -p /var/lib/redis/6380
chmod 777 /var/log/redis/
chmod 777 /var/lib/redis/6380

# Ubuntu(默认已存在,若不存在,执行以下命令)
# mkdir -p /var/lib/redis/6380
# chmod 777 /var/lib/redis/6380

# 5. 修改主节点配置文件(redis.conf),开启后台守护进程(可选,方便后台运行)
vim redis.conf
daemonize yes  # 将no改为yes

关键提醒:主节点的配置文件,默认不需要做任何额外修改,只需要开启后台守护进程即可;所有修改,都只针对从节点!

3.2 三种主从配置方式

Redis 提供了三种配置主从关系的方式,效果完全一致,只是适用场景不同:

方式 1:配置文件配置(永久生效,生产环境推荐)

这种方式是将主从配置写入从节点的配置文件中,重启 Redis 实例后,主从关系依然保留,永久生效,适合生产环境稳定部署。

操作步骤
  1. 编辑从节点配置文件(redis-slave-6380.conf):

    复制代码
    vim /usr/local/redis/conf/redis-slave-6380.conf  # CentOS
    # vim /etc/redis/redis-slave-6380.conf  # Ubuntu
  2. 在配置文件末尾,添加以下配置(指定主节点的 IP 和端口):

    复制代码
    # 格式:slaveof 主节点IP 主节点端口
    # 本地部署,主节点IP为127.0.0.1,端口6379
    slaveof 127.0.0.1 6379
  3. 启动主节点(6379):

    复制代码
    redis-server /usr/local/redis/conf/redis.conf  # CentOS
    # redis-server /etc/redis/redis.conf  # Ubuntu
  4. 启动从节点(6380):

    复制代码
    redis-server /usr/local/redis/conf/redis-slave-6380.conf  # CentOS
    # redis-server /etc/redis/redis-slave-6380.conf  # Ubuntu
  5. 验证主从关系是否建立成功。

优点与缺点
  • 优点:永久生效,重启 Redis 实例后,主从关系不会丢失;配置集中,便于管理;适合生产环境;
  • 缺点:修改配置后,需要重启 Redis 实例才能生效,不能动态调整。
方式 2:启动命令行配置(临时生效,测试环境推荐)

这种方式是在启动从节点时,通过--slaveof参数指定主节点的 IP 和端口,无需修改配置文件,快速搭建主从关系,临时生效,重启从节点后,主从关系丢失,适合本地测试、临时验证。

操作步骤(全程实战)
  1. 确保主节点已启动(6379):

    复制代码
    redis-server /usr/local/redis/conf/redis.conf  # CentOS
    # redis-server /etc/redis/redis.conf  # Ubuntu
  2. 启动从节点时,指定--slaveof参数:

    复制代码
    # 格式:redis-server 从节点配置文件路径 --port 从节点端口 --slaveof 主节点IP 主节点端口
    redis-server /usr/local/redis/conf/redis-slave-6380.conf --port 6380 --slaveof 127.0.0.1 6379  # CentOS
    # redis-server /etc/redis/redis-slave-6380.conf --port 6380 --slaveof 127.0.0.1 6379  # Ubuntu
  3. 验证主从关系是否建立成功。

优点与缺点
  • 优点:无需修改配置文件,快速搭建,适合测试;无需重启实例,即时生效;
  • 缺点:临时生效,重启从节点后,主从关系丢失;不适合生产环境。
方式 3:Redis 命令行配置(动态生效,临时切换主节点推荐)

这种方式是在从节点启动后,通过 Redis 客户端(redis-cli)执行slaveof命令,动态指定主节点,无需修改配置文件,无需重启 Redis 实例,临时生效,重启从节点后,主从关系丢失,适合临时切主、故障恢复时的动态调整。

操作步骤
  1. 启动主节点(6379)和从节点(6380),此时从节点未配置主节点,是独立节点:

    复制代码
    # 启动主节点
    redis-server /usr/local/redis/conf/redis.conf  # CentOS
    # redis-server /etc/redis/redis.conf  # Ubuntu
    
    # 启动从节点(不指定--slaveof参数)
    redis-server /usr/local/redis/conf/redis-slave-6380.conf  # CentOS
    # redis-server /etc/redis/redis-slave-6380.conf  # Ubuntu
  2. 连接从节点的 Redis 客户端:

    复制代码
    redis-cli -p 6380  # 连接端口6380的从节点
  3. 在从节点客户端,执行slaveof命令,指定主节点:

    复制代码
    127.0.0.1:6380> slaveof 127.0.0.1 6379
    OK  # 回复OK,说明主从关系配置成功
  4. 验证主从关系是否建立成功。

优点与缺点
  • 优点:动态生效,无需修改配置文件,无需重启实例;可以快速切换主节点(比如主节点宕机,快速切换到其他主节点);
  • 缺点:临时生效,重启从节点后,主从关系丢失;配置分散,不便于生产环境长期管理。
三种方式对比总结
配置方式 生效方式 重启后是否保留 适用场景 优点 缺点
配置文件配置 永久生效 是 生产环境 永久生效、配置集中、便于管理 需要重启实例才能生效
启动命令行配置 临时生效 否 测试环境、临时验证 无需修改配置、快速搭建 重启后丢失、不适合生产
Redis 命令行配置 动态生效 否 临时切主、故障恢复 动态调整、无需重启、快速切主 重启后丢失、配置分散

3.3 验证主从复制是否成功

配置完主从关系后,我们需要通过多种方法验证,确保主从复制正常工作,数据能够正常同步:

方法 1:查看主从节点进程(验证实例是否启动)

首先,验证主节点(6379)和从节点(6380)的 Redis 实例是否正常启动,进程是否存在:

复制代码
# 查看Redis相关进程(CentOS/Ubuntu通用)
ps -ef | grep redis
正常输出(解析):
复制代码
root      1234  0.0  0.1 141888  2048 ?        Ssl  10:00   0:00 redis-server 127.0.0.1:6379  # 主节点进程,端口6379
root      1235  0.0  0.1 141888  2048 ?        Ssl  10:01   0:00 redis-server 127.0.0.1:6380  # 从节点进程,端口6380
root      1236  0.0  0.0 112824   988 pts/0    S+   10:02   0:00 grep --color=auto redis

关键判断:存在两个 Redis 进程,分别对应端口 6379(主)和 6380(从),说明实例启动成功。

方法 2:查看端口监听(验证端口是否正常开放)

通过netstat命令,查看主从节点的端口是否正常监听,确保能够建立连接:

复制代码
# 查看6379和6380端口的监听状态(CentOS/Ubuntu通用)
netstat -nlpt | grep -E "6379|6380"
正常输出(解析):
复制代码
tcp        0      0 127.0.0.1:6379          0.0.0.0:*               LISTEN      1234/redis-server  # 6379端口监听,主节点
tcp        0      0 127.0.0.1:6380          0.0.0.0:*               LISTEN      1235/redis-server  # 6380端口监听,从节点

✅ 关键判断:两个端口都处于LISTEN状态,说明端口正常开放,能够接收连接。

方法 3:使用 info replication 命令(核心方法,查看复制状态)

info replication是查看主从复制状态的唯一核心命令,可以查看节点角色、主从连接状态、复制偏移量、从节点列表等所有关键信息,我们分别在主节点和从节点执行,逐行解析输出。

(1)主节点(6379)执行 info replication
复制代码
# 连接主节点客户端
redis-cli -p 6379
# 执行info replication命令
127.0.0.1:6379> info replication
正常输出:
复制代码
# Replication  # 复制相关信息的标识,以下所有字段都属于复制模块
role:master    # 节点角色:master(主节点),若为从节点,此处为slave
connected_slaves:1  # 当前连接的从节点数量:1个(我们只部署了1个从节点)
slave0:ip=127.0.0.1,port=6380,state=online,offset=100,lag=0  # 从节点详情(slave0表示第一个从节点,多个从节点会有slave1、slave2...)
# ip=127.0.0.1:从节点的IP地址(本地部署,所以是127.0.0.1)
# port=6380:从节点的端口
# state=online:从节点的状态(online=在线,offline=离线)
# offset=100:从节点当前的复制偏移量(表示从节点已经同步到主节点的第100字节数据)
# lag=0:从节点的延迟(单位:秒),0表示无延迟,延迟越低越好
master_replid:2fbd35a8b8401b22eb92ff49ad5e42250b3e7a06  # 主节点的复制ID(replid),唯一标识主节点的数据版本
master_replid2:0000000000000000000000000000000000000000  # 主节点的备用复制ID(replid2),主节点默认是0,只有从节点晋升为主节点后,才会有值
master_repl_offset:100  # 主节点当前的复制偏移量(表示主节点已经执行到第100字节的命令)
second_repl_offset:-1   # 备用复制偏移量,默认-1,无实际意义
repl_backlog_active:1   # 复制积压缓冲区的状态:1=开启,0=关闭(有从节点连接时,自动开启)
repl_backlog_size:1048576  # 复制积压缓冲区的大小:1048576字节=1MB(默认大小)
repl_backlog_first_byte_offset:1  # 复制积压缓冲区的起始偏移量
repl_backlog_histlen:100  # 复制积压缓冲区中已保存的数据长度:100字节(和主节点offset一致)

主节点正常状态判断:

  • role=master;
  • connected_slaves≥1(我们部署了 1 个,所以是 1);
  • slave0 的 state=online;
  • master_repl_offset 和 slave0 的 offset 一致(此处都是 100),说明数据同步正常。
(2)从节点(6380)执行 info replication
复制代码
# 连接从节点客户端
redis-cli -p 6380
# 执行info replication命令
127.0.0.1:6380> info replication
正常输出:
复制代码
# Replication
role:slave                 # 节点角色:slave(从节点)
master_host:127.0.0.1      # 主节点的IP地址(我们配置的主节点IP)
master_port:6379           # 主节点的端口(我们配置的主节点端口)
master_link_status:up      # 主从连接状态:up=正常,down=断开(核心判断字段)
master_last_io_seconds_ago:1  # 距离上次与主节点通信的时间:1秒(越小越好,说明通信频繁)
master_sync_in_progress:0  # 是否正在进行数据同步:0=未同步,1=正在同步(正常情况下是0)
slave_repl_offset:170      # 从节点当前的复制偏移量(和主节点的master_repl_offset一致,说明数据同步完成)
slave_priority:100         # 从节点的优先级(故障转移时,优先级越高,越容易被选为新主节点,默认100,值越小优先级越高)
slave_read_only:1          # 从节点的只读模式:1=开启,0=关闭(默认开启,禁止写操作)
connected_slaves:0         # 从节点连接的从节点数量:0(我们的从节点没有下属从节点)
master_replid:2fbd35a8b8401b22eb92ff49ad5e42250b3e7a06  # 主节点的复制ID(和主节点的master_replid完全一致,说明同步的是正确的主节点)
master_replid2:0000000000000000000000000000000000000000  # 备用复制ID(默认0,未切换过主节点)
master_repl_offset:170     # 主节点的复制偏移量(和自身的slave_repl_offset一致,说明数据同步正常)
second_repl_offset:-1
repl_backlog_active:1      # 复制积压缓冲区开启(从节点也会有缓冲区,用于切主时的同步)
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:170

从节点正常状态判断:

  • role=slave;
  • master_host 和 master_port 正确(127.0.0.1:6379);
  • master_link_status=up;
  • slave_repl_offset 和 master_repl_offset 一致;
  • master_replid 和主节点的 master_replid 一致。
方法 4:数据同步测试(最直观,验证数据能否正常同步)

前面的方法都是查看状态,最直观的方法是 "主节点写入数据,从节点查询数据",验证数据能否正常同步,我们测试不同数据类型的同步(string、hash、list),确保所有数据类型都能正常同步。

测试 1:string 类型数据同步
复制代码
# 主节点(6379)写入数据
127.0.0.1:6379> set name "redis-master"
OK
127.0.0.1:6379> set age 20
OK

# 从节点(6380)查询数据
127.0.0.1:6380> get name
"redis-master"  # 同步成功
127.0.0.1:6380> get age
"20"            # 同步成功
测试 2:hash 类型数据同步
复制代码
# 主节点(6379)写入hash数据
127.0.0.1:6379> hset user:1 id 1 name zhangsan age 25
(integer) 3  # 成功写入3个字段

# 从节点(6380)查询hash数据
127.0.0.1:6380> hgetall user:1
1) "id"
2) "1"
3) "name"
4) "zhangsan"
5) "age"
6) "25"  # 同步成功
测试 3:list 类型数据同步
复制代码
# 主节点(6379)写入list数据
127.0.0.1:6379> lpush list1 a b c d
(integer) 4  # 成功写入4个元素

# 从节点(6380)查询list数据
127.0.0.1:6380> lrange list1 0 -1
1) "d"
2) "c"
3) "b"
4) "a"  # 同步成功(lpush是从左边插入,所以查询结果是倒序)
测试 4:从节点写操作禁止(验证只读模式)
复制代码
# 从节点(6380)执行写命令
127.0.0.1:6380> set name "redis-slave"
(error) READONLY You can't write against a read only slave.  # 报错,提示只读模式,不能写操作

关键判断:主节点写入的所有数据,从节点都能正常查询;从节点执行写命令报错,说明只读模式正常,主从复制工作正常。

3.4 断开复制与切主操作

在生产环境中,经常会遇到 "主节点宕机,需要切换从节点为主节点""需要更换主节点,将从节点切换到新主节点" 等场景,这就需要用到 "断开复制" 和 "切主操作"

3.4.1 断开主从复制(slaveof no one)

从节点执行slaveof no one命令,可以断开与当前主节点的复制关系,同时,从节点会晋升为主节点,不再同步原主节点的数据,但会保留原有同步过来的数据。

操作步骤
复制代码
# 连接从节点(6380)客户端
redis-cli -p 6380

# 执行断开复制命令
127.0.0.1:6380> slaveof no one
OK  # 回复OK,说明断开成功

# 查看复制状态,验证从节点晋升为主节点
127.0.0.1:6380> info replication
输出解析(核心变化):
复制代码
# Replication
role:master  # 角色从slave变为master,晋升为主节点
connected_slaves:0  # 没有连接的从节点(刚晋升,还未配置从节点)
master_replid:3a7b4c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b  # 生成了新的复制ID(不再和原主节点一致)
master_replid2:2fbd35a8b8401b22eb92ff49ad5e42250b3e7a06  # 备用复制ID,保存原主节点的复制ID
master_repl_offset:200  # 复制偏移量继续累积
断开复制的核心流程
  1. 从节点断开与原主节点的 TCP 连接,停止接收原主节点的同步数据;
  2. 从节点的角色从slave变为master,生成新的复制 ID(replid);
  3. 从节点的备用复制 ID(replid2),保存原主节点的复制 ID,用于后续可能的重连、切主;
  4. 从节点保留原有同步过来的数据,不会清空;
  5. 从节点的只读模式依然开启(slave_read_only=1),若需要作为新主节点处理写请求,需要手动关闭只读模式(后续演示)。
注意事项
  • 断开复制后,从节点晋升为主节点,但默认还是只读模式,不能处理写请求,需要手动关闭只读模式;
  • 断开复制后,原主节点的connected_slaves数量会减少 1(原主节点会检测到从节点下线,断开连接);
  • 断开复制后,若原主节点恢复,从节点(已晋升为主节点)不会自动重新同步原主节点的数据,需要手动执行slaveof命令重新配置。
bash 复制代码
redis-server /usr/local/redis/conf/redis-master-6381.conf  # CentOS
# redis-server /etc/redis/redis-master-6381.conf  # Ubuntu

# 5. 验证新主节点启动成功(查看进程和端口)
ps -ef | grep redis-6381  # 存在进程即成功
netstat -nlpt | grep 6381  # 端口处于LISTEN状态即成功
  1. 确认原主节点(6379)已宕机(模拟生产故障):

    复制代码
    # 停止原主节点(6379)
    redis-cli -p 6379 shutdown
    # 验证原主节点已宕机(无进程、无端口监听)
    ps -ef | grep redis-6379  # 无输出即宕机
    netstat -nlpt | grep 6379  # 无输出即宕机
  2. 连接需要切主的从节点(6380),执行切主命令:

    复制代码
    # 连接从节点(6380)客户端
    redis-cli -p 6380
    # 执行切主命令,切换到新主节点(6381)
    127.0.0.1:6380> slaveof 127.0.0.1 6381
    OK  # 回复OK,说明切主命令执行成功,开始切换流程
  3. 验证切主是否成功(核心:查看从节点复制状态):

    复制代码
    127.0.0.1:6380> info replication
    正常输出(重点看切主后的变化):

    Replication

    role:slave # 依然是从节点,只是主节点变了(切主后不会自动晋升为主节点,除非执行slaveof no one)
    master_host:127.0.0.1 # 主节点IP变为新主节点(6381)的IP,与我们配置的新主节点一致
    master_port:6381 # 主节点端口变为6381(核心变化,证明切主成功,不再连接原主节点6379)
    master_link_status:up # 与新主节点的连接状态:up(正常),说明已成功与新主节点建立连接
    master_last_io_seconds_ago:1 # 距离上次与新主节点通信的时间:1秒,通信正常
    master_sync_in_progress:0 # 是否正在进行数据同步:0=未同步(已完成同步),若刚执行切主命令,此处会显示1(正在全量同步)
    slave_repl_offset:50 # 从节点当前的复制偏移量,与新主节点的master_repl_offset(50)完全一致,说明同步完成
    slave_priority:100 # 从节点优先级不变,依然是100
    slave_read_only:1 # 只读模式依然开启,禁止写操作
    connected_slaves:0 # 该从节点没有下属从节点(若为树形拓扑,此处会显示下属从节点数量)
    master_replid:4c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d # 新主节点(6381)的复制ID,与新主节点执行info replication显示的master_replid完全一致
    master_replid2:3a7b4c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b # 备用复制ID,保存上一个主节点(6380曾晋升的主节点)的复制ID,用于后续若再次切回原主节点的同步验证
    master_repl_offset:50 # 新主节点的复制偏移量,与自身slave_repl_offset一致,数据同步正常
    second_repl_offset:-1
    repl_backlog_active:1 # 复制积压缓冲区开启,跟随新主节点的缓冲区配置
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:1
    repl_backlog_histlen:50

切主成功核心判断:

  1. master_host和master_port变为新主节点的 IP 和端口;
  2. master_link_status:up(与新主节点连接正常);
  3. master_replid与新主节点的master_replid完全一致;
  4. slave_repl_offset与新主节点的master_repl_offset完全一致。
切主操作的核心流程

切主操作不是简单的 "更换主节点 IP",而是有完整的内部流程,每一步都会影响数据和服务,结合我们上面的实战场景(从节点 6380 从 6379 切到 6381):

  1. 断开与旧主节点的连接:从节点(6380)收到slaveof 127.0.0.1 6381命令后,立即断开与原主节点(6379)的 TCP 连接,停止接收原主节点的任何同步数据,无论原主节点是否在线(即使原主节点恢复,也不会再连接);
  2. **清空自身所有数据:这是最关键、最容易被忽略的一步!从节点会彻底清空自身内存中所有已同步的数据(包括原主节点同步过来的 string、hash、list 等所有数据),目的是避免与新主节点的数据混淆,保证后续同步的数据与新主节点完全一致;**切主后,从节点(6380)查询之前同步的name字段,会返回nil(数据已清空):
复制代码
   127.0.0.1:6380> get name
   (nil)  # 数据已清空,与新主节点保持一致(新主节点6381未写入name字段)
  1. 与新主节点建立连接并同步数据:从节点主动与新主节点(6381)建立 TCP 连接,执行完整的同步流程 ------ 由于是第一次与新主节点连接,会执行全量复制 (发送PSYNC ? -1),接收新主节点的 RDB 文件、缓冲区命令,加载数据,完成同步;
  2. 进入实时命令复制阶段:全量复制完成后,从节点跟随新主节点,进入实时同步状态,新主节点执行的所有写命令,都会实时同步到该从节点,保证数据一致。
切主操作的注意事项
  1. 数据清空的影响:切主会清空从节点所有数据,若从节点正在提供读服务,切主期间会出现 "读不到数据"(返回 nil),建议在业务低峰期执行切主操作,或提前做好数据备份;

  2. 新主节点的要求:新主节点必须是 "独立的主节点"(role:master),不能是其他主节点的从节点(除非是树形拓扑的中间层从节点),否则会导致同步失败;错误场景:若新主节点(6381)本身是 6379 的从节点(role:slave),从节点 6380 切主到 6381,会报错:

    复制代码
    (error) ERR SLAVE OF is not allowed on a slave node  # 提示:从节点不能作为其他从节点的主节点
  3. 切主后的验证:切主后,必须执行 3 步验证:① 查看info replication确认连接和同步状态;② 新主节点写入数据,从节点查询验证同步;③ 从节点执行写命令,确认只读模式正常;

  4. 多从节点切主:若有多个从节点需要切换到新主节点,需逐个执行切主命令,避免多个从节点同时向新主节点发起全量复制,拖垮新主节点;

  5. 原主节点恢复后的处理:切主后,若原主节点(6379)恢复,不会自动与从节点(6380)重新建立连接,若需要切回原主节点,需在从节点(6380)再次执行slaveof 127.0.0.1 6379,并再次经历 "清空数据→全量同步" 的流程。

3.5 从节点只读模式详解

之前我们提到 "从节点默认只读",但很多同学会有疑问:"能不能关闭只读模式?关闭后有什么影响?"

3.5.1 只读模式的核心配置(两种配置方式)

从节点的只读模式由slave-read-only参数控制,默认值为yes(开启),支持两种配置方式:

  1. 配置文件配置(永久生效):

    复制代码
    # 从节点配置文件(redis-slave-6380.conf)
    slave-read-only yes  # 开启只读(默认),改为no即关闭
  2. 命令行配置(临时生效,重启失效):

    复制代码
    # 连接从节点(6380)
    redis-cli -p 6380
    # 关闭只读模式
    127.0.0.1:6380> config set slave-read-only no
    OK
    # 开启只读模式
    127.0.0.1:6380> config set slave-read-only yes
    OK
3.5.2 关闭只读模式的实战演示(为什么不建议关闭)

我们关闭从节点的只读模式,看看会发生什么,理解 "为什么生产环境绝对禁止关闭":

  1. 关闭从节点(6380)只读模式:

    复制代码
    127.0.0.1:6380> config set slave-read-only no
    OK
  2. 从节点(6380)写入数据:

    复制代码
    127.0.0.1:6380> set age 30
    OK  # 关闭只读后,可正常写入数据
    127.0.0.1:6380> get age
    "30"
  3. 查看主节点(6381)的数据:

    复制代码
    127.0.0.1:6381> get age
    (nil)  # 主节点没有该数据,从节点的修改不会同步给主节点
  4. 主节点(6381)写入相同 key 的数据:

    复制代码
    127.0.0.1:6381> set age 40
    OK
  5. 再次查看从节点(6380)的 age 字段:

    复制代码
    127.0.0.1:6380> get age
    "40"  # 主节点的修改会覆盖从节点的手动修改,导致从节点手动写入的数据丢失
3.5.3 关闭只读模式的危害
  1. 主从数据不一致:从节点手动写入的数据,不会同步给主节点,也不会同步给其他从节点,导致自身数据与主节点不一致;
  2. 数据丢失:主节点执行相同 key 的写命令时,会覆盖从节点手动写入的数据,导致从节点的手动修改丢失,无法恢复;
  3. 业务错乱:客户端从该从节点读取到 "不一致的数据",会导致业务逻辑错乱(比如查询到旧数据、错误数据),排查难度极大。

结论:无论什么场景,生产环境的从节点,必须保持只读模式开启 (slave-read-only=yes),禁止关闭!

3.6 网络传输延迟配置详解

之前提到repl-disable-tcp-nodelay参数控制主从网络传输效率,这里拆解参数作用、两种配置的实战效果、适用场景:

3.6.1 核心参数解析
复制代码
# 从节点配置文件(redis-slave-6380.conf),主节点无需配置该参数
repl-disable-tcp-nodelay no  # 默认值:no(开启TCP_NODELAY)
  • 参数值说明:no= 开启 TCP_NODELAY,yes= 关闭 TCP_NODELAY;
  • 核心作用:控制主节点发送同步命令的 "实时性" 和 "带宽消耗",本质是 "trade-off(取舍)"------ 实时性和带宽消耗,二选一。
3.6.2 两种配置的实战对比
参数值 核心逻辑 主从延迟 带宽消耗 适用场景 实战效果演示
no(默认,开启 TCP_NODELAY) 主节点执行完写命令后,立即发送给从节点,不合并数据包,哪怕是 1 字节的小命令 极低(毫秒级),几乎无延迟 较大(每个小命令都单独发送,占用额外带宽) 同机房、局域网部署(主从节点在同一机房,带宽充足,优先保证实时性) 主节点执行set a 1,从节点几乎同时收到命令,slave_repl_offset立即同步,延迟≤1ms
yes(关闭 TCP_NODELAY) 主节点会合并小数据包(默认等待 40ms,由 Linux 内核控制),将多个小命令合并成一个数据包发送 较高(约 40ms,取决于内核配置),延迟明显 较小(合并数据包,减少发送次数,节省带宽) 跨机房、公网部署(主从节点在不同机房,带宽昂贵,优先节省带宽) 主节点 1 秒内执行 10 个set小命令,主节点会合并成 1 个数据包,40ms 后发送给从节点,从节点延迟约 40ms
3.6.3 生产配置建议
  1. 若主从节点在同一机房 / 局域网 (90% 的生产场景):保持默认值repl-disable-tcp-nodelay no,优先保证主从数据实时性,机房带宽充足,无需担心带宽消耗;
  2. 若主从节点在不同机房 / 跨公网 (特殊场景,如异地备份):修改为repl-disable-tcp-nodelay yes,优先节省带宽,接受 40ms 左右的延迟,避免跨机房带宽被占满;
  3. 补充:若跨机房部署,且想降低延迟,可修改 Linux 内核参数tcp_delack_min(调整合并等待时间),但不建议新手操作,避免影响其他服务。

3.7 密码验证的完整实战

生产环境中,Redis 主节点必须设置密码(防止未授权访问),此时从节点必须配置masterauth参数,与主节点密码一致,否则无法建立主从连接,同步失败。

3.7.1 步骤 1:主节点(6379)设置密码(3 种方式,实战演示)

主节点设置密码,支持 3 种方式,与从节点的配置方式对应,生产推荐 "配置文件方式"(永久生效)。

方式 1:配置文件方式(永久生效,生产推荐)
复制代码
# 编辑主节点配置文件(redis.conf)
vim /usr/local/redis/conf/redis.conf  # CentOS
# vim /etc/redis/redis.conf  # Ubuntu

# 添加/修改密码参数(任意位置,建议放在配置文件开头)
requirepass 123456  # 密码设为123456(生产环境建议设复杂密码,如Redis@2024!)

# 重启主节点(修改配置文件后,必须重启才能生效)
redis-cli -p 6379 shutdown  # 停止主节点
redis-server /usr/local/redis/conf/redis.conf  # 重启主节点

验证主节点密码:

复制代码
# 连接主节点,未输入密码,执行命令报错
redis-cli -p 6379
127.0.0.1:6379> get name
(error) NOAUTH Authentication required.  # 提示需要密码验证

# 输入密码,验证成功
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> get name
"redis-master"  # 可正常执行命令
方式 2:命令行方式(临时生效,重启失效,测试用)
复制代码
# 连接主节点(已启动,未设密码)
redis-cli -p 6379
# 执行命令设置密码
127.0.0.1:6379> config set requirepass 123456
OK

# 验证密码(同上,需auth 123456才能执行命令)

❌ 缺点:主节点重启后,密码失效,恢复无密码状态,不适合生产。

方式 3:启动命令行参数(临时生效,重启失效,测试用)
复制代码
# 启动主节点时,通过--requirepass参数设密码
redis-server /usr/local/redis/conf/redis.conf --requirepass 123456  # CentOS
# redis-server /etc/redis/redis.conf --requirepass 123456  # Ubuntu
3.7.2 步骤 2:从节点(6380)配置主节点密码(3 种方式,与主节点对应)

从节点需要配置masterauth参数,与主节点的requirepass密码一致,否则无法建立主从连接,同步失败。

方式 1:配置文件方式(永久生效,生产推荐)
复制代码
# 编辑从节点配置文件(redis-slave-6380.conf)
vim /usr/local/redis/conf/redis-slave-6380.conf  # CentOS
# vim /etc/redis/redis-slave-6380.conf  # Ubuntu

# 添加/修改masterauth参数,与主节点密码一致
masterauth 123456

# 重启从节点(修改配置文件后,必须重启)
redis-cli -p 6380 shutdown
redis-server /usr/local/redis/conf/redis-slave-6380.conf --slaveof 127.0.0.1 6379  # CentOS
# redis-server /etc/redis/redis-slave-6380.conf --slaveof 127.0.0.1 6379  # Ubuntu
方式 2:命令行方式(临时生效,重启失效,测试用
复制代码
# 连接从节点(已启动,未配置masterauth)
redis-cli -p 6380
# 执行命令配置masterauth
127.0.0.1:6380> config set masterauth 123456
OK
# 重新配置主从关系(使密码生效)
127.0.0.1:6380> slaveof 127.0.0.1 6379
OK
方式 3:启动命令行参数(临时生效,重启失效,测试用)
复制代码
# 启动从节点时,通过--masterauth参数设密码
redis-server /usr/local/redis/conf/redis-slave-6380.conf --slaveof 127.0.0.1 6379 --masterauth 123456  # CentOS
# redis-server /etc/redis/redis-slave-6380.conf --slaveof 127.0.0.1 6379 --masterauth 123456  # Ubuntu
3.7.3 步骤 3:验证密码配置成功(核心,避免同步失败)
复制代码
# 查看从节点(6380)的复制状态
127.0.0.1:6380> info replication

正常输出(核心判断):

复制代码
master_link_status:up  # 连接正常,密码验证成功
master_host:127.0.0.1
master_port:6379
# 其他字段正常,slave_repl_offset与主节点一致
3.7.4 密码错误的故障场景

若从节点masterauth与主节点requirepass不一致,会导致主从连接失败,同步失败,我们实战模拟该场景,讲解排查和解决方法:

故障现象
  1. 从节点执行info replication,显示master_link_status:down;

  2. 从节点日志中出现报错(核心排查依据):

    复制代码
    # 查看从节点日志(CentOS)
    cat /var/log/redis/redis-6380.log
    # 报错信息
    1235:M 10 Feb 2026 11:30:00.000 * Connecting to MASTER 127.0.0.1:6379
    1235:M 10 Feb 2026 11:30:00.001 * MASTER <-> REPLICA sync started
    1235:M 10 Feb 2026 11:30:00.001 # Error: Authentication failed.  # 关键报错:认证失败
    1235:M 10 Feb 2026 11:30:01.000 * Retrying with SYNC after a failed PSYNC with target: master
  3. 主节点执行info replication,connected_slaves:0(未连接到从节点)。

故障原因

从节点masterauth参数值,与主节点requirepass参数值不一致(比如主节点密码 123456,从节点配置 12345)。

解决方法(3 步)
  1. 确认主节点密码:

    复制代码
    redis-cli -p 6379
    127.0.0.1:6379> auth 123456
    OK
    127.0.0.1:6379> config get requirepass  # 查看主节点密码
    1) "requirepass"
    2) "123456"
  2. 确认并修改从节点masterauth:

    复制代码
    redis-cli -p 6380
    127.0.0.1:6380> config get masterauth  # 查看从节点当前配置的密码
    1) "masterauth"
    2) "12345"  # 发现密码错误
    127.0.0.1:6380> config set masterauth 123456  # 修改为正确密码
    OK
  3. 重新建立主从连接,验证恢复:

    复制代码
    127.0.0.1:6380> slaveof 127.0.0.1 6379
    OK
    127.0.0.1:6380> info replication
    master_link_status:up  # 连接正常,同步恢复

3.8 主从复制常见故障排查

学习主从复制,不仅要会配置、懂原理,还要会排查故障 ------ 生产环境中,主从复制很容易出现各种问题(同步失败、连接中断、数据不一致等)

故障现象
  • 从节点info replication显示master_link_status:down;
  • 从节点日志报错:Connecting to MASTER 127.0.0.1:6379 failed: Connection refused;
  • 主节点info replication显示connected_slaves:0。
排查步骤(实战,一步一步来)
  1. 排查主节点是否正常运行:

    复制代码
    ps -ef | grep redis-6379  # 查看主节点进程是否存在
    netstat -nlpt | grep 6379  # 查看主节点端口是否监听
  2. 排查主节点 IP 和端口是否正确:

    复制代码
    # 从节点查看当前配置的主节点IP和端口
    127.0.0.1:6380> config get masterhost masterport
    1) "masterhost"
    2) "127.0.0.1"  # 确认IP正确
    3) "masterport"
    4) "6379"       # 确认端口正确
  3. 排查网络是否通畅(主从节点之间能否 ping 通、端口能否访问):

    复制代码
    # 从节点所在服务器ping主节点IP(本地部署ping 127.0.0.1)
    ping 127.0.0.1
    # 测试主节点端口是否可访问(用telnet)
    telnet 127.0.0.1 6379
    # 若telnet成功,会显示Connected to 127.0.0.1;失败则显示Connection refused
  4. 排查主节点是否设置密码,从节点是否配置 masterauth(参考 3.7.4)。

常见故障原因及解决方法
故障原因 解决方法
主节点未启动 启动主节点:redis-server /usr/local/redis/conf/redis.conf
主节点端口冲突(6379 被其他进程占用) 1. 查看占用 6379 端口的进程:netstat -nlpt grep 6379;2. 停止该进程:kill -9 进程 ID;3. 重启主节点
从节点配置的主节点 IP / 端口错误 1. 命令行修改:config set masterhost 正确 IP、config set masterport 正确端口;2. 配置文件修改(永久生效),重启从节点
主从节点之间网络不通(跨机房 / 防火墙拦截) 1. 检查防火墙规则,开放主节点 6379 端口和从节点 6380 端口;2. 确认主从节点 IP 可互通
主节点设密码,从节点未配置 masterauth 从节点配置 masterauth,与主节点密码一致,重新建立主从连接
故障 2:主从连接正常,但数据同步失败(slave_repl_offset 与 master_repl_offset 不一致)
故障现象
  • 从节点info replication显示master_link_status:up,但slave_repl_offset远小于主节点的master_repl_offset;
  • 主节点写入新数据,从节点查询不到;
  • 从节点日志报错:MASTER <-> REPLICA sync failed: RDB transfer error。
排查步骤
  1. 查看从节点日志,确认同步失败的具体原因(核心排查依据):

    复制代码
    cat /var/log/redis/redis-6380.log
  2. 查看主节点是否正在执行 bgsave(全量复制时,主节点需要生成 RDB 文件):

    复制代码
    127.0.0.1:6379> info persistence
    rdb_bgsave_in_progress:0  # 0=未执行,1=正在执行(若正在执行,等待执行完成)
  3. 查看从节点的数据目录权限,是否有写入权限(RDB 文件无法保存):

    复制代码
    # 查看从节点数据目录权限(CentOS)
    ls -ld /var/lib/redis/6380
    # 若权限不足(如只有读权限),会显示dr--r--r--,需要修改权限
  4. 验证主节点是否有数据,从节点是否清空旧数据(切主后未同步,可能是数据未清空)。

常见故障原因及解决方法
故障原因 解决方法
主节点 bgsave 失败(无法生成 RDB 文件) 1. 查看主节点日志,确认 bgsave 失败原因(如内存不足);2. 释放主节点内存(删除无用数据);3. 手动执行 bgsave:127.0.0.1:6379> bgsave;4. 重新建立主从连接
从节点数据目录权限不足(无法保存 RDB 文件) 修改数据目录权限:chmod 777 /var/lib/redis/6380,重启从节点
主节点 RDB 文件损坏 1. 删除主节点损坏的 RDB 文件(默认路径 /var/lib/redis/dump.rdb);2. 手动执行 bgsave 生成新的 RDB 文件;3. 重新建立主从连接
主从节点 Redis 版本不一致(如主节点 7.0,从节点 5.0) 升级从节点 Redis 版本,与主节点一致(Redis 版本向下兼容,但跨版本可能导致同步失败)
故障 3:从节点执行写命令报错(READONLY You can't write against a read only slave)
故障现象
  • 从节点执行写命令(如 set、del),报错:(error) READONLY You can't write against a read only slave.;
  • 业务客户端从从节点读取数据正常,但写入数据失败。
故障原因

从节点默认开启只读模式(slave-read-only=yes),禁止执行写命令,这是 Redis 的默认规则,目的是保证主从数据一致。

解决方法(分场景)
  1. 若业务需要写入数据:禁止在从节点写入,将写请求转发到主节点,从节点只处理读请求;
  2. 若为测试场景,临时需要写入:关闭从节点只读模式(config set slave-read-only no),但测试完成后,必须重新开启(config set slave-read-only yes);
  3. 若误关闭了只读模式,导致数据不一致:执行slaveof no one断开复制,再执行slaveof 主节点IP 主节点端口重新建立连接,从节点会清空数据,重新全量同步,恢复数据一致。
故障 4:主节点宕机后,从节点无法提供服务
故障现象
  • 主节点宕机(进程消失、端口关闭);
  • 从节点info replication显示master_link_status:down;
  • 业务客户端从从节点读取数据正常,但写入数据失败(因为主节点宕机);
  • 重新启动主节点后,从节点无法自动重新建立主从连接。
故障原因
  1. 主从复制没有 "自动故障转移" 功能,主节点宕机后,从节点不会自动晋升为主节点,也不会自动重新连接主节点;
  2. 从节点只读模式开启,无法处理写请求;
  3. 从节点与主节点断开连接后,不会自动重新建立连接(需要手动触发)。
解决方法(生产实战,两步恢复服务)
  1. 临时恢复写服务(将从节点晋升为主节点):

    复制代码
    # 连接从节点(6380)
    redis-cli -p 6380
    # 断开与原主节点的连接,晋升为主节点
    127.0.0.1:6380> slaveof no one
    OK
    # 关闭只读模式(允许处理写请求)
    127.0.0.1:6380> config set slave-read-only no
    OK
    # 验证晋升成功
    127.0.0.1:6380> info replication
    role:master  # 已晋升为主节点
    connected_slaves:0

    ✅ 此时,业务客户端可将写请求转发到 6380,读请求继续在 6380 处理,服务恢复正常。

  2. 主节点恢复后,重新建立主从关系(将原主节点作为从节点,同步新主节点数据):

    复制代码
    # 启动原主节点(6379)
    redis-server /usr/local/redis/conf/redis.conf
    
    # 连接原主节点(6379)
    redis-cli -p 6379
    # 执行slaveof,将原主节点作为从节点,同步新主节点(6380)的数据
    127.0.0.1:6379> slaveof 127.0.0.1 6380
    OK
    # 验证同步状态
    127.0.0.1:6379> info replication
    role:slave
    master_host:127.0.0.1
    master_port:6380
    master_link_status:up  # 连接正常,同步恢复

    ✅ 恢复后,新主节点(6380)处理写请求,原主节点(6379)作为从节点,处理读请求,回到主从架构。

故障 5:复制积压缓冲区不足,导致频繁全量复制
故障现象
  • 主从网络闪断后,重新连接,不是执行部分复制,而是执行全量复制;
  • 主节点日志报错:Replica requested PSYNC but offset is out of backlog;
  • 从节点日志报错:Full resync from master requested because offset is out of backlog;
  • 频繁全量复制,导致主节点 CPU、内存、带宽占用过高,响应变慢。
故障原因

复制积压缓冲区默认大小为 1MB(repl_backlog_size=1048576),当主从网络中断时间过长,主节点执行的写命令过多,超过缓冲区大小,缓冲区中的旧命令被覆盖,从节点重连后,自身的offset不在缓冲区的可用范围内,主节点无法补发丢失的数据,只能执行全量复制。

解决方法(生产推荐)
  1. 调大复制积压缓冲区大小(根据业务写并发调整,一般设为 64MB~128MB):

    复制代码
    # 主节点执行(临时生效,重启失效)
    127.0.0.1:6379> config set repl_backlog_size 67108864  # 64MB(67108864字节)
    OK
    # 从节点也需要调大(临时生效)
    127.0.0.1:6380> config set repl_backlog_size 67108864
    OK
  2. 配置文件修改(永久生效,生产推荐):

    复制代码
    # 主节点配置文件(redis.conf)
    vim /usr/local/redis/conf/redis.conf
    repl_backlog_size 67108864  # 添加/修改为64MB
    
    # 从节点配置文件(redis-slave-6380.conf)
    vim /usr/local/redis/conf/redis-slave-6380.conf
    repl_backlog_size 67108864
    
    # 重启主从节点,使配置生效
  3. 优化网络,减少网络中断时间(如部署在同一机房,检查网络稳定性,避免频繁闪断)。

✅ 配置建议:写并发越高、网络越不稳定,缓冲区设越大;一般 64MB 可满足绝大多数中小业务场景,写并发极高的场景(如每秒 10 万写 QPS),可设为 128MB。

故障 6:主从数据不一致(主节点有数据,从节点无数据 / 数据错误)
故障现象
  • 主节点执行写命令后,从节点查询不到该数据,或数据不一致(如主节点set a 1,从节点get a返回nil);
  • 主从节点info replication显示slave_repl_offset与master_repl_offset一致,但数据依然不一致;
  • 从节点曾关闭过只读模式,手动写入过数据。
常见故障原因及解决方法
故障原因 解决方法
从节点曾关闭只读模式,手动写入数据,后被主节点命令覆盖 1. 断开从节点复制:slaveof no one;2. 清空从节点数据:flushall;3. 重新建立主从连接:slaveof 主节点 IP 主节点端口,全量同步恢复
主从同步过程中,从节点宕机,重启后未重新同步 1. 从节点重启后,执行 slaveof 主节点 IP 主节点端口;2. 查看 info replication,确认同步完成
主节点执行了flushall/flushdb命令,从节点同步失败 1. 若主节点有 RDB/AOF 备份,恢复主节点数据;2. 从节点重新建立主从连接,全量同步;3. 禁止在主节点手动执行 flushall/flushdb(风险极高)
复制过程中,网络中断,部分命令未同步,且缓冲区被覆盖 1. 调大复制积压缓冲区;2. 从节点重新建立主从连接,全量同步;3. 优化网络

3.9 主从复制实战总结

  1. 配置原则:主节点不修改配置(仅开启守护进程、设密码),所有配置都在从节点;
  2. 三种配置方式:生产用 "配置文件方式"(永久生效),测试用 "命令行 / 启动参数方式"(临时生效);
  3. 核心验证命令:info replication(查看主从状态)、ps -ef | grep redis(查看进程)、netstat -nlpt(查看端口);
  4. 关键参数:slaveof(配置主从)、masterauth(主节点密码)、slave-read-only=yes(只读模式)、repl_backlog_size(复制缓冲区)、repl-disable-tcp-nodelay(传输延迟);
  5. 故障排查核心:先看日志,再用 info replication 排查,最后检查进程 / 端口 / 网络;
  6. 生产避坑:从节点只读模式禁止关闭、主节点必须设密码、复制缓冲区调大、避免频繁全量复制。

四、第三章:主从复制三大拓扑结构

前面我们讲解了主从复制的配置、故障排查,接下来详细拆解三种拓扑结构的实战部署步骤、性能对比、适用场景

4.1 一主一从结构

4.1.1 架构回顾
复制代码
主节点(Master)6379(老师)
        ↓(知识传递=数据同步)
从节点(Slave)6380(助教)
  • 核心特点:1 主 1 从,从节点仅作为主节点的 "热备份"+"读请求分担者",不承担其他角色;
  • 适用场景:小型业务、低并发场景(读 QPS≤1 万)、对可用性要求不高(可接受手动故障转移)。
4.1.2 实战部署步骤(完整,CentOS/Ubuntu 通用)

我们基于之前的部署基础,搭建一主一从架构,步骤如下:

  1. 部署主节点(6379):

    复制代码
    # 1. 配置主节点(redis.conf)
    vim /usr/local/redis/conf/redis.conf  # CentOS
    # vim /etc/redis/redis.conf  # Ubuntu
    daemonize yes  # 开启后台运行
    requirepass 123456  # 设密码(生产必配)
    
    # 2. 启动主节点
    redis-server /usr/local/redis/conf/redis.conf
    
    # 3. 验证主节点
    redis-cli -p 6379 -a 123456  # 直接输入密码连接
    127.0.0.1:6379> info replication
    role:master
    connected_slaves:0  # 暂无从节点,正常
  2. 部署从节点(6380):

    复制代码
    # 1. 复制配置文件,修改参数
    cp /usr/local/redis/conf/redis.conf /usr/local/redis/conf/redis-slave-6380.conf
    vim /usr/local/redis/conf/redis-slave-6380.conf
    
    # 修改核心参数
    port 6380  # 端口6380
    daemonize yes  # 后台运行
    pidfile /var/run/redis_6380.pid
    logfile "/var/log/redis/redis-6380.log"
    dir /var/lib/redis/6380
    slaveof 127.0.0.1 6379  # 配置主节点
    masterauth 123456  # 主节点密码
    slave-read-only yes  # 开启只读
    repl_backlog_size 67108864  # 64MB缓冲区
    repl-disable-tcp-nodelay no  # 同机房,低延迟
    
    # 2. 创建目录,修改权限
    mkdir -p /var/lib/redis/6380
    chmod 777 /var/lib/redis/6380
    
    # 3. 启动从节点
    redis-server /usr/local/redis/conf/redis-slave-6380.conf
    
    # 4. 验证从节点
    redis-cli -p 6380 -a 123456
    127.0.0.1:6380> info replication
    role:slave
    master_host:127.0.0.1
    master_port:6379
    master_link_status:up  # 连接正常
    slave_repl_offset:xxx  # 与主节点一致
  3. 验证架构正常(数据同步 + 读写分离):

    复制代码
    # 主节点写入数据
    127.0.0.1:6379> set user:2 id 2 name lisi age 28
    OK
    
    # 从节点查询数据(读请求)
    127.0.0.1:6380> hgetall user:2
    1) "id"
    2) "2"
    3) "name"
    4) "lisi"
    5) "age"
    6) "28"  # 同步成功
    
    # 从节点执行写命令(禁止)
    127.0.0.1:6380> set user:2 age 29
    (error) READONLY You can't write against a read only slave.  # 正常报错

4.1.3 一主一从的优化配置

为提升可用性和性能,一主一从架构建议做如下优化(核心:主节点关持久化,从节点开持久化):

核心配置差异

节点类型 持久化配置 配置说明
主节点(redis.conf) 关闭持久化 save ""(关闭 RDB)appendonly no(关闭 AOF)
从节点(redis-slave-6380.conf) 开启持久化 save 900 1(900 秒 1 次写操作生成 RDB)save 300 10(300 秒 10 次写操作生成 RDB)appendonly yes(开启 AOF)appendfilename "appendonly-6380.aof"(指定 AOF 文件名)appendfsync everysec(每秒同步 AOF,性能 + 安全兼顾)

一主一从架构优点

  1. 配置简单、易部署维护:仅需配置 1 个从节点,拓扑设计简单,故障排查快,适合新手 / 小型业务;
  2. 数据备份 + 读写分离:从节点作为热备份,主节点故障可恢复数据;从节点分担读请求,缓解主节点压力;
  3. 资源消耗低:仅需 2 台服务器(生产)/2 个实例(测试),CPU / 内存 / 带宽占用少,部署成本低。

一主一从架构缺点

  1. 读并发能力有限:单从节点仅能分担部分读请求,读 QPS 上限约 2-3 万,无法支撑≥5 万 QPS 的高并发读场景;
  2. 可用性依赖手动切换:主节点宕机后,从节点无法自动晋升,需人工执行slaveof no one+ 关闭只读,恢复服务需 1-5 分钟,期间写服务不可用;
  3. 无冗余备份:仅 1 个从节点,若从节点宕机,主从同时失效,数据备份丢失风险高。

4.2 一主多从结构

4.2.1 架构说明

复制代码
主节点(Master)6379(老师)
        ↓(数据同步)
从节点(Slave)6380(助教1)、6381(助教2)、6382(助教3)...(多个助教)

核心特点:1 个主节点 + N 个从节点(N≥2,生产建议 2-5 个),所有从节点直接同步主节点数据;从节点承担读请求,主节点仅处理写请求。

适用场景:中大型业务、高并发读场景(读 QPS≥3 万)、对可用性有一定要求(多从节点冗余备份),如电商商品详情、资讯 APP 文章列表等读多写少场景。

4.2.2 实战部署步骤(基于一主一从扩展,CentOS/Ubuntu 通用)

在一主一从(6379 主、6380 从)基础上,新增 6381、6382 两个从节点,搭建一主三从架构,步骤如下:

步骤 1:新增从节点配置文件(6381、6382)

复制现有从节点配置文件,修改端口、pid、日志、数据目录等唯一参数:

复制代码
# 进入Redis配置文件目录
# CentOS:
cd /usr/local/redis/conf/
# Ubuntu:
# cd /etc/redis/

# 1. 生成6381从节点配置文件
cp redis-slave-6380.conf redis-slave-6381.conf

# 2. 编辑6381配置文件,修改核心参数(仅改端口相关5项)
vim redis-slave-6381.conf
# 需修改的参数:
port 6381  # 端口改为6381
pidfile /var/run/redis_6381.pid  # pid文件改为6381
logfile "/var/log/redis/redis-6381.log"  # 日志文件改为6381
dir /var/lib/redis/6381  # 数据目录改为6381
# 其他参数(slaveof、masterauth、slave-read-only等)与6380一致,无需修改

# 3. 生成6382从节点配置文件
cp redis-slave-6380.conf redis-slave-6382.conf

# 4. 编辑6382配置文件,修改核心参数
vim redis-slave-6382.conf
# 需修改的参数:
port 6382  # 端口改为6382
pidfile /var/run/redis_6382.pid
logfile "/var/log/redis/redis-6382.log"
dir /var/lib/redis/6382
# 其他参数与6380一致
步骤 2:创建数据目录并修改权限

避免启动时报 "权限不足 / 目录不存在" 错误:

复制代码
# CentOS(Ubuntu若目录不存在也执行)
mkdir -p /var/lib/redis/6381
mkdir -p /var/lib/redis/6382
chmod 777 /var/lib/redis/6381
chmod 777 /var/lib/redis/6382
步骤 3:启动新增从节点(6381、6382)

确保主节点(6379)已正常运行,再启动新从节点:

复制代码
# 启动6381从节点
# CentOS:
redis-server /usr/local/redis/conf/redis-slave-6381.conf
# Ubuntu:
# redis-server /etc/redis/redis-slave-6381.conf

# 启动6382从节点
# CentOS:
redis-server /usr/local/redis/conf/redis-slave-6382.conf
# Ubuntu:
# redis-server /etc/redis/redis-slave-6382.conf
步骤 4:验证一主三从架构是否正常(4 步全覆盖)
验证 1:查看所有节点进程(确认实例启动)
复制代码
ps -ef | grep redis

正常输出(核心判断):

复制代码
root      1234  0.0  0.1 141888  2048 ?        Ssl  10:00   0:00 redis-server 127.0.0.1:6379  # 主节点
root      1235  0.0  0.1 141888  2048 ?        Ssl  10:01   0:00 redis-server 127.0.0.1:6380  # 从节点6380
root      1236  0.0  0.1 141888  2048 ?        Ssl  10:02   0:00 redis-server 127.0.0.1:6381  # 从节点6381
root      1237  0.0  0.1 141888  2048 ?        Ssl  10:03   0:00 redis-server 127.0.0.1:6382  # 从节点6382

✅ 四个进程都存在 → 所有节点启动成功。

验证 2:查看主节点(6379)复制状态(确认从节点连接)
复制代码
# 连接主节点
redis-cli -p 6379 -a 123456
# 执行复制状态查询
127.0.0.1:6379> info replication

正常输出(核心解析):

复制代码
# Replication
role:master
connected_slaves:3  # 连接的从节点数量为3(6380、6381、6382)
slave0:ip=127.0.0.1,port=6380,state=online,offset=200,lag=0
slave1:ip=127.0.0.1,port=6381,state=online,offset=200,lag=0
slave2:ip=127.0.0.1,port=6382,state=online,offset=200,lag=0
master_replid:2fbd35a8b8401b22eb92ff49ad5e42250b3e7a06
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:200
repl_backlog_active:1
repl_backlog_size:67108864  # 64MB缓冲区(优化项)
repl_backlog_first_byte_offset:1
repl_backlog_histlen:200

✅ 核心判断:connected_slaves=3,所有从节点state=online,offset与主节点一致。

验证 3:查看新增从节点(6381、6382)复制状态
复制代码
# 连接6381从节点
redis-cli -p 6381 -a 123456
127.0.0.1:6381> info replication

正常输出(核心解析):

复制代码
# Replication
role:slave
master_host:127.0.0.1  # 主节点IP正确
master_port:6379       # 主节点端口正确
master_link_status:up  # 与主节点连接正常
slave_repl_offset:200  # 与主节点offset一致,同步正常
master_replid:2fbd35a8b8401b22eb92ff49ad5e42250b3e7a06
slave_read_only:1      # 只读模式开启
connected_slaves:0     # 无下属从节点
验证 4:数据同步测试(主节点写入,所有从节点查询)
复制代码
# 主节点(6379)写入新数据(hash类型)
127.0.0.1:6379> hset product:1 id 1 name "手机" price 3999 stock 100
(integer) 4

# 从节点6380查询
127.0.0.1:6380> hgetall product:1
1) "id"
2) "1"
3) "name"
4) "手机"
5) "price"
6) "3999"
7) "stock"
8) "100"  # 同步成功

# 从节点6381查询(结果与6380一致)
127.0.0.1:6381> hgetall product:1  # 同步成功

# 从节点6382查询(结果与6380一致)
127.0.0.1:6382> hgetall product:1  # 同步成功

✅ 所有从节点都能查询到主节点写入的数据,说明数据同步正常,一主三从架构部署成功。

4.2.3 一主多从架构的优化配置

在之前基础上,新增 3 个优化配置,进一步提升性能和可用性:

优化 1:主节点开启 "复制积压缓冲区" 自动扩容(Redis 5.0 + 支持)
复制代码
# 主节点(6379)执行(临时生效)
127.0.0.1:6379> config set repl_backlog_ttl 3600  # 缓冲区空闲3600秒(1小时)后自动收缩到默认大小
OK
127.0.0.1:6379> config set repl_backlog_size 67108864  # 初始大小64MB
OK

✅ 核心作用:缓冲区自动根据实际需求扩容 / 收缩,避免缓冲区过小导致频繁全量复制,过大浪费内存。

优化 2:从节点开启 "只读 replicas"(Redis 6.0 + 支持)
复制代码
# 从节点配置文件(redis-slave-6380.conf、6381.conf、6382.conf)
replica-read-only yes  # Redis 6.0+将slave-read-only改为replica-read-only,功能一致,推荐使用新参数

✅ 核心作用:与slave-read-only=yes一致,开启只读模式,Redis 6.0 + 推荐使用新参数,兼容性更好。

优化 3:配置从节点优先级,指定故障转移时的晋升顺序
复制代码
# 从节点配置文件,给不同从节点设置不同优先级(值越小,优先级越高)
# 6380从节点(优先晋升为主节点)
slave-priority 50
# 6381从节点(次优先)
slave-priority 100
# 6382从节点(最低优先级)
slave-priority 150

✅ 核心作用:主节点宕机后,手动切换时,优先选择优先级高的从节点晋升为主节点(如 6380 优先),避免随意选择导致性能不足。

4.2.5 一主多从结构的优缺点
优点(4 点,生产核心优势)
  1. 读并发能力强:多个从节点分担读请求,读 QPS 可线性提升(如 3 个从节点,读 QPS 可达 6-9 万),支撑高并发读场景;
  2. 数据冗余备份:多个从节点,即使某个从节点宕机,其他从节点仍可提供读服务和数据备份,降低数据丢失风险;
  3. 主节点压力小:主节点仅处理写请求,读请求全部由从节点承担,主节点 CPU、内存、带宽压力大幅降低,提升写请求处理效率;
  4. 部署灵活:可根据读并发需求,动态新增从节点(无需修改主节点配置,仅需配置新从节点的slaveof),扩容成本低。
缺点(3 点,生产避坑重点)
  1. 主节点是性能瓶颈和单点故障:所有写请求都集中在主节点,写并发过高(如每秒 10 万写 QPS)会导致主节点过载;主节点宕机后,所有写服务不可用,需要手动切换从节点为主节点;
  2. 主节点同步压力大:主节点需要向所有从节点同步数据,从节点数量越多,主节点的同步压力越大(CPU、带宽消耗越高),建议从节点数量不超过 5 个;
  3. 主从延迟风险:主节点写请求同步到多个从节点,可能出现延迟不一致(如某个从节点延迟 10ms,某个延迟 20ms),导致不同从节点返回的数据不一致(极端场景)。

4.3 树形拓扑结构(主 - 从 - 从,跨机房 / 读并发极高场景)

4.3.1 架构说明
复制代码
主节点(Master)6379(老师)
        ↓(数据同步)
从节点(Slave)6380(助教组长,中间层从节点)
        ↓(数据同步)
从节点(Slave)6381(助教)、6382(助教)...(下层从节点)
  • 核心特点:1 个主节点 + 1 个(或多个)中间层从节点 + N 个下层从节点;主节点仅同步数据到中间层从节点,中间层从节点同步数据到下层从节点;中间层从节点既承担读请求,又作为 "二级主节点",转发主节点的数据到下层从节点;
  • 适用场景:跨机房部署(如主节点 + 中间层从节点在机房 A,下层从节点在机房 B)、读并发极高(读 QPS≥10 万)、主节点同步压力过大(从节点数量超过 5 个)的场景。
4.3.2 实战部署步骤(基于一主多从扩展,CentOS/Ubuntu 通用)

我们搭建 "1 主 1 中间层 2 下层" 的树形拓扑:

  • 主节点:6379(机房 A,仅处理写请求,同步数据到 6380);
  • 中间层从节点:6380(机房 A,同步 6379 数据,转发到 6381、6382,承担部分读请求);
  • 下层从节点:6381、6382(机房 B,同步 6380 数据,承担大部分读请求)。
步骤 1:修改中间层从节点(6380)配置,开启复制转发

中间层从节点需要开启 "复制转发" 功能,才能将主节点同步过来的数据,转发到自身的从节点(6381、6382),默认情况下,Redis 从节点不会转发数据,需手动开启:

复制代码
# 编辑中间层从节点(6380)配置文件
vim /usr/local/redis/conf/redis-slave-6380.conf  # CentOS
# Ubuntu:vim /etc/redis/redis-slave-6380.conf

# 添加/修改以下参数,开启复制转发(Redis 5.0+参数)
replica-serve-stale-data yes  # 从节点同步期间,允许返回旧数据(避免读请求报错)
replica-read-only yes  # 依然开启只读模式(中间层从节点也禁止写操作)
repl-diskless-sync yes  # 开启无磁盘同步(可选,提升同步效率,减少磁盘IO)
repl-diskless-sync-delay 5  # 无磁盘同步延迟5秒(等待所有下层从节点连接)

# 关键参数:开启复制转发(Redis 3.2+支持,旧版本用slave-skip-min-slaves-to-write)
replica-forwarded-commands yes  # 开启复制转发,中间层从节点会将主节点的同步命令,转发到下层从节点

✅ 注意:中间层从节点的slaveof参数依然是127.0.0.1 6379,同步主节点数据,无需修改。

步骤 2:重启中间层从节点(6380),使配置生效
复制代码
# 停止6380从节点
redis-cli -p 6380 -a 123456 shutdown

# 重启6380从节点(CentOS)
redis-server /usr/local/redis/conf/redis-slave-6380.conf
# Ubuntu:redis-server /etc/redis/redis-slave-6380.conf

# 验证中间层从节点配置(确认复制转发开启)
redis-cli -p 6380 -a 123456
127.0.0.1:6380> config get replica-forwarded-commands
1) "replica-forwarded-commands"
2) "yes"  # 已开启,正确
步骤 3:修改下层从节点(6381、6382)配置,同步中间层从节点

之前我们的 6381、6382 是同步主节点 6379,现在修改为同步中间层从节点 6380,步骤如下:

(1)修改 6381 从节点配置
复制代码
vim /usr/local/redis/conf/redis-slave-6381.conf  # CentOS
# Ubuntu:vim /etc/redis/redis-slave-6381.conf

# 修改slaveof参数,从同步6379改为同步6380
slaveof 127.0.0.1 6380  # 同步中间层从节点6380
# masterauth参数不变(依然是123456,与主节点密码一致,因为中间层从节点转发的命令需要密码验证)
masterauth 123456
# 其他参数(port、pid、log等)不变
(2)修改 6382 从节点配置
复制代码
vim /usr/local/redis/conf/redis-slave-6382.conf  # CentOS
# Ubuntu:vim /etc/redis/redis-slave-6382.conf

# 修改slaveof参数,同步中间层从节点6380
slaveof 127.0.0.1 6380
masterauth 123456
# 其他参数不变
步骤 4:重启下层从节点(6381、6382),使配置生效
复制代码
# 停止6381从节点
redis-cli -p 6381 -a 123456 shutdown
# 重启6381(CentOS)
redis-server /usr/local/redis/conf/redis-slave-6381.conf

# 停止6382从节点
redis-cli -p 6382 -a 123456 shutdown
# 重启6382(CentOS)
redis-server /usr/local/redis/conf/redis-slave-6382.conf
步骤 5:验证树形拓扑架构是否正常
验证 1:查看主节点(6379)复制状态(仅连接中间层从节点 6380)
复制代码
127.0.0.1:6379> info replication
正常输出(核心解析):
复制代码
role:master
connected_slaves:1  # 仅连接1个从节点(6380,中间层),下层从节点(6381、6382)不直接连接主节点
slave0:ip=127.0.0.1,port=6380,state=online,offset=300,lag=0
master_repl_offset:300
# 其他参数正常

✅ 核心判断:connected_slaves=1,仅 6380 连接主节点,符合树形拓扑逻辑。

验证 2:查看中间层从节点(6380)复制状态(连接主节点 + 下层从节点)
复制代码
127.0.0.1:6380> info replication
正常输出(核心解析):
复制代码
# Replication
role:slave  # 依然是从节点(同步主节点6379)
master_host:127.0.0.1
master_port:6379
master_link_status:up  # 与主节点连接正常
slave_repl_offset:300  # 与主节点offset一致,同步正常
connected_slaves:2  # 连接2个下层从节点(6381、6382),作为中间层主节点
slave0:ip=127.0.0.1,port=6381,state=online,offset=300,lag=0  # 下层从节点6381
slave1:ip=127.0.0.1,port=6382,state=online,offset=300,lag=0  # 下层从节点6382
master_replid:2fbd35a8b8401b22eb92ff49ad5e42250b3e7a06  # 与主节点replid一致
replica-forwarded-commands:yes  # 复制转发已开启

✅ 核心判断:role=slave(同步主节点),connected_slaves=2(连接下层从节点),复制转发开启,符合中间层角色定位。

验证 3:查看下层从节点(6381、6382)复制状态(同步中间层 6380)
复制代码
127.0.0.1:6381> info replication
正常输出(核心解析):
复制代码
role:slave
master_host:127.0.0.1  # 主节点IP改为6380(中间层),不再是6379
master_port:6380       # 主节点端口改为6380
master_link_status:up  # 与中间层从节点连接正常
slave_repl_offset:300  # 与中间层、主节点offset一致,同步正常
master_replid:2fbd35a8b8401b22eb92ff49ad5e42250b3e7a06  # 与主节点replid一致(中间层转发的)
slave_read_only:1
connected_slaves:0

✅ 6382 从节点验证方法相同,输出与 6381 一致,说明下层从节点同步正常。

验证 4:数据同步测试(主节点写入,所有从节点查询)
复制代码
# 主节点(6379)写入新数据(list类型)
127.0.0.1:6379> lpush order:list 1001 1002 1003 1004
(integer) 4

# 中间层从节点(6380)查询
127.0.0.1:6380> lrange order:list 0 -1
1) "1004"
2) "1003"
3) "1002"
4) "1001"  # 同步成功(主节点→中间层)

# 下层从节点6381查询
127.0.0.1:6381> lrange order:list 0 -1  # 同步成功(中间层→下层)

# 下层从节点6382查询
127.0.0.1:6382> lrange order:list 0 -1  # 同步成功(中间层→下层)

✅ 所有从节点(中间层、下层)都能查询到主节点写入的数据,说明数据转发、同步正常,树形拓扑生效。

验证 5:复制转发测试(中间层同步主节点命令,转发到下层)
复制代码
# 主节点(6379)执行删除命令
127.0.0.1:6379> del order:list
(integer) 1

# 中间层从节点(6380)查询,确认删除
127.0.0.1:6380> lrange order:list 0 -1
(empty list or set)  # 已删除

# 下层从节点6381查询,确认删除(中间层转发了删除命令)
127.0.0.1:6381> lrange order:list 0 -1
(empty list or set)  # 已删除

✅ 主节点的删除命令,通过中间层从节点转发到下层从节点,所有从节点数据同步删除,说明复制转发功能正常。

4.3.4 树形拓扑结构的优缺点
优点
  1. 降低主节点同步压力:主节点仅同步数据到中间层从节点,无需同步到所有下层从节点,从节点数量再多,也不会大幅增加主节点的 CPU、带宽消耗;
  2. 节省跨机房带宽:跨机房部署时,主节点仅需发送 1 份数据到中间层从节点,中间层转发到下层从节点,避免多份数据跨机房传输,节省昂贵的跨机房带宽;
  3. 读并发能力极强:下层从节点数量可灵活扩展(如 10 个 +),读 QPS 可突破 10 万,支撑超高并发读场景;
  4. 跨机房部署友好:解决跨机房同步延迟高、带宽消耗大的问题,实现 "主机房写、从机房读",提升从机房业务的访问速度(就近读)。
缺点
  1. 架构复杂、维护成本高:涉及主节点、中间层从节点、下层从节点,配置、故障排查都比一主多从复杂(如中间层从节点宕机,所有下层从节点同步失败);
  2. 中间层从节点是单点故障:中间层从节点宕机后,所有下层从节点无法同步数据,读服务可能受影响(若下层从节点有持久化,可临时提供读服务,但数据不会更新);
  3. 主从延迟叠加:主节点→中间层从节点有延迟,中间层→下层从节点有延迟,总延迟是两者之和(如主→中间层 10ms,中间层→下层 10ms,总延迟 20ms),延迟比一主多从高;
  4. 配置复杂:中间层从节点需要开启复制转发,下层从节点需要配置正确的同步对象,跨机房部署还需要配置防火墙、公网 IP,对运维能力要求较高。

4.4 三种拓扑结构对比总结

拓扑结构 架构示意图 核心优点 核心缺点 适用场景 生产部署建议
一主一从 主 6379→从 6380 1. 配置简单、易维护;2. 资源消耗低;3. 实现基础备份与读写分离 1. 读并发有限(≤3 万 QPS);2. 无冗余备份;3. 手动故障转移 小型业务、低并发读、对可用性要求不高(如小型网站、内部系统) 测试 / 小型生产,用 2 台服务器,主节点关闭持久化,从节点开启持久化
一主多从 主 6379→从 6380、6381、6382 1. 读并发强(≤9 万 QPS);2. 数据冗余备份;3. 主节点压力小;4. 扩容灵活 1. 主节点是单点故障;2. 主节点同步压力大(从节点≤5 个);3. 主从有毫秒级延迟 中大型业务、高并发读、读多写少(如电商、资讯 APP、社交平台) 生产首选,用 3-6 台服务器,主节点关闭持久化,从节点开启持久化,从节点数量 2-5 个
树形拓扑 主 6379→中间层 6380→下层 6381、6382 1. 主节点同步压力极低;2. 节省跨机房带宽;3. 读并发极强(≤10 万 + QPS);4. 跨机房友好 1. 架构复杂、维护成本高;2. 中间层是单点故障;3. 主从延迟叠加 超高并发读、跨机房部署、从节点数量 > 5 个(如大型电商、全国性 APP) 跨机房 / 超高并发场景,用 6 台以上服务器,中间层从节点至少 2 个(避免单点),跨机房关闭 TCP_NODELAY

五、第四章:主从复制底层原理深度拆解

前面我们讲解了主从复制的配置、拓扑、故障排查,都是 "实战层面" 的内容,接下来拆解 "底层原理"------ 为什么主节点的数据能同步到从节点?全量复制和部分复制的区别是什么?PSYNC 命令如何工作?

5.1 主从复制的核心同步流程

无论哪种拓扑结构,主从复制的核心同步流程都分为 "三个阶段",全程结合 "老师 - 助教" 类比,让大家直观理解:

  1. 建立连接阶段(握手阶段):助教(从节点)主动找到老师(主节点),说明 "我要跟随你,同步你的知识(数据)",老师确认身份(密码验证)后,与助教建立连接;
  2. 数据同步阶段(核心阶段):老师根据助教的情况(首次跟随 / 中途走神),决定是 "把所有课件都抄给助教(全量复制)",还是 "只把助教漏抄的几页课件给助教(部分复制)",助教接收课件(数据),并保存起来;
  3. 实时同步阶段(维持阶段):后续老师讲的新内容(主节点执行的写命令),都会实时抄给助教(从节点),助教实时更新自己的课件(数据),确保与老师的课件完全一致,同时,助教和老师会定期确认 "对方是否在线"(心跳检测)。

简单总结:连接→同步(全量 / 部分)→实时同步 + 心跳检测,这三个阶段循环往复,维持主从复制正常运行。

5.2 建立连接阶段

建立连接阶段,是主从复制的第一步,核心是 "从节点主动发起连接,主节点验证身份,建立 TCP 连接,协商同步参数":

5.2.1 建立连接的 5 个详细步骤
步骤 通俗类比(老师 - 助教) 技术细节(实战解析) 实战验证方法
步骤 1:从节点发起连接请求 助教找到老师,说 "我要跟随你,同步你的知识" 从节点执行slaveof 主节点IP 主节点端口命令(配置文件 / 命令行),主动向主节点发起 TCP 连接请求,请求端口为住节点的 Redis 端口(6379) 从节点日志会显示:Connecting to MASTER 127.0.0.1:6379
步骤 2:主节点接收连接请求 老师停下讲课,问助教 "你是谁?(验证身份)" 主节点收到从节点的 TCP 连接请求后,创建一个新的客户端连接(专门用于与该从节点通信),并向从节点发送 "欢迎连接" 的响应 主节点日志会显示:Accepted repl connection from 127.0.0.1:xxxx(xxxx 是从节点的随机端口)
步骤 3:密码验证(若主节点设密码) 助教出示学生证(身份验证),老师确认无误 从节点向主节点发送AUTH 密码命令(密码由masterauth配置),主节点验证密码是否正确,若正确,进入下一步;若错误,拒绝连接 密码错误时,从节点日志显示:Error: Authentication failed;正确则显示:MASTER <-> REPLICA sync started
步骤 4:协商同步参数 老师问助教 "你之前有没有跟随过其他老师?有没有漏抄的课件?",助教回答 "没有 / 有,漏抄到第 100 页" 从节点向主节点发送自身的 "复制偏移量(offset)" 和 "复制 ID(replid)",告知主节点 "我当前的同步进度";主节点根据从节点的 offset 和 replid,决定执行全量复制还是部分复制 从节点执行info replication,可查看自身的slave_repl_offset和master_replid
步骤 5:建立同步关系,进入数据同步阶段 老师确认后,说 "好,我现在把课件给你",助教准备接收 主节点确认从节点的同步进度后,标记该从节点为 "已连接从节点",更新自身的connected_slaves计数;从节点标记自身为 "slave",更新master_host、master_port等参数,双方进入数据同步阶段 主节点info replication显示该从节点state=online;从节点info replication显示master_link_status=up
5.2.2 实战演示:建立连接的全过程(查看日志)

我们通过查看主从节点的日志,直观看到建立连接的每一步,实战验证:

(1)从节点(6380)日志(建立连接的关键信息)
复制代码
cat /var/log/redis/redis-6380.log  # CentOS
5.2.3 建立连接阶段的关键注意事项(实战必避坑)
  1. 从节点发起连接后,会自动清空自身所有数据 (日志中 "Flushing old data"),目的是避免与主节点数据混淆,无论从节点之前是否有数据,都会被清空;❌ 错误场景:从节点有重要数据,未备份就执行slaveof命令,导致数据丢失,无法恢复;✅ 解决方案:执行slaveof命令前,先备份从节点数据(save生成 RDB,或bgsave)。
  2. 主节点接收从节点连接后,会创建一个专门的客户端连接用于同步,该客户端仅处理复制相关命令(如发送 RDB、写命令),不处理普通业务客户端的请求;
  3. 密码验证失败时,从节点会持续重试连接(默认每 1 秒重试一次),日志中会反复出现 "Authentication failed",直到密码配置正确;
  4. 从节点执行slaveof no one后,会断开与主节点的连接,晋升为独立主节点,此时再执行slaveof 主节点IP 端口,会再次发起连接,清空自身数据,重新同步。

5.3 数据同步阶段(核心阶段)------ 全量复制(首次同步 / 重大同步)

数据同步阶段分为 "全量复制" 和 "部分复制",其中全量复制是最核心、最耗时的同步方式,适用于

  • "从节点首次同步主节点"
  • "从节点 offset 超出主节点复制缓冲区范围"
  • "从节点 replid 与主节点不一致"

三种场景

5.3.1 全量复制的通俗类比(老师 - 助教)

助教是第一次跟随老师,没有任何之前的课件(数据),老师需要:① 先把自己所有的课件(主节点所有数据)整理成一本手册(RDB 文件);② 把手册抄给助教(发送 RDB 文件);③ 助教收到手册后,把手册上的内容全部抄到自己的笔记本上(加载 RDB 文件);④ 老师在整理手册的过程中,新讲的内容(主节点执行的写命令),单独记在一张纸上,等助教抄完手册后,再把这张纸上的内容抄给助教(发送缓冲区命令);⑤ 助教抄完所有内容后,笔记本上的内容就和老师完全一致了。

5.3.2 全量复制的 6 个详细步骤
步骤 通俗类比 主节点操作(技术细节) 从节点操作(技术细节) 实战日志验证(核心日志)
步骤 1:从节点发起全量复制请求 助教对老师说 "我是第一次来,没有任何课件,麻烦把所有课件都给我" 无(等待从节点请求) 从节点发送PSYNC ? -1命令(?表示不知道之前的 replid,-1表示 offset 为 - 1,即首次同步),请求全量复制 从节点日志:Replica asks for synchronization;主节点日志:Full resync requested by replica
步骤 2:主节点准备全量复制(生成 RDB 文件 + 记录缓冲区命令) 老师开始整理所有课件(生成 RDB),同时新讲的内容单独记在纸上(缓冲区命令) 1. 主节点执行BGSAVE命令,后台生成 RDB 文件(不阻塞主节点处理写请求);2. 主节点创建一个 "复制缓冲区"(repl_backlog),将BGSAVE执行期间所有的写命令(如 set、del)都记录到缓冲区中;3. 主节点生成一个新的master_replid(复制 ID),用于标识本次全量复制的数据集 无(等待主节点发送数据) 主节点日志:Starting BGSAVE for SYNC with target: disk;Background saving terminated with success
步骤 3:主节点发送 RDB 文件到从节点 老师把整理好的课件手册(RDB 文件)抄给助教 1. BGSAVE执行成功后,主节点将 RDB 文件的大小、校验和等信息发送给从节点;2. 主节点通过之前建立的 TCP 连接,将 RDB 文件逐字节发送给从节点;3. 发送期间,主节点继续将新的写命令记录到复制缓冲区 1. 从节点接收主节点发送的 RDB 文件信息,准备接收 RDB 文件;2. 从节点创建一个临时文件,用于保存接收的 RDB 文件;3. 从节点持续接收 RDB 文件字节,写入临时文件 主节点日志:Sending RDB to replica;从节点日志:MASTER <-> REPLICA sync: receiving 1st byte from master
步骤 4:从节点加载 RDB 文件(清空旧数据 + 导入 RDB) 助教收到手册后,清空自己的笔记本(旧数据),把手册上的内容全部抄到笔记本上 无(持续记录缓冲区命令) 1. 从节点接收完 RDB 文件后,校验 RDB 文件的完整性(避免文件传输损坏);2. 从节点执行FLUSHALL命令,清空自身所有旧数据;3. 从节点加载 RDB 文件,将 RDB 文件中的数据导入到自身内存中(加载期间,从节点会阻塞,无法处理读请求);4. 加载完成后,从节点更新自身的slave_repl_offset为 RDB 文件对应的 offset(即主节点生成 RDB 时的 offset) 从节点日志:MASTER <-> REPLICA sync: Flushing old data;MASTER <-> REPLICA sync: Loading DB in memory
步骤 5:主节点发送复制缓冲区中的命令 老师把整理手册期间新讲的内容(缓冲区命令),抄给助教 1. 主节点查询复制缓冲区,将BGSAVE执行期间记录的所有写命令,按顺序发送给从节点;2. 发送完成后,主节点更新自身的master_repl_offset,并记录从节点的当前 offset 1. 从节点接收主节点发送的缓冲区命令,按顺序执行每一条命令;2. 每执行一条命令,从节点就更新自身的slave_repl_offset,确保与主节点的 offset 一致;3. 执行完成后,从节点的数据集与主节点完全一致 主节点日志:Sending buffered commands to replica;从节点日志:MASTER <-> REPLICA sync: Finished with success
步骤 6:全量复制完成,进入实时同步阶段 助教抄完所有内容,笔记本与老师完全一致,后续老师新讲的内容,实时抄录 主节点标记该从节点为 "online",更新connected_slaves列表,后续执行的所有写命令,都会实时发送给该从节点 从节点标记master_link_status=up,后续持续接收主节点发送的写命令,实时执行,维持数据一致 主节点日志:Synchronization with replica succeeded;从节点日志:MASTER <-> REPLICA sync: Finished with success
5.3.3 全量复制的实战验证

我们通过实战命令和日志,验证全量复制的整个流程:

验证 1:查看主节点 BGSAVE 执行情况(步骤 2)
复制代码
# 连接主节点6379
redis-cli -p 6379 -a 123456
# 查看持久化信息,确认BGSAVE执行成功
127.0.0.1:6379> info persistence
rdb_bgsave_in_progress:0  # 0=未执行,1=正在执行(全量复制时会显示1)
rdb_bgsave_status:ok      # BGSAVE执行成功
rdb_last_save_time:1739172000  # 最近一次BGSAVE的时间(对应全量复制的时间)
验证 2:查看从节点 RDB 加载情况(步骤 4)
复制代码
# 连接从节点6380
redis-cli -p 6380 -a 123456
# 查看从节点复制信息,确认RDB加载完成
127.0.0.1:6380> info replication
slave_repl_offset:1000  # 与主节点master_repl_offset一致,说明加载完成
master_replid:2fbd35a8b8401b22eb92ff49ad5e42250b3e7a06  # 与主节点master_replid一致(全量复制生成的新replid)
master_replid2:0000000000000000000000000000000000000000  # 首次同步,无历史replid
验证 3:查看主从节点 offset 一致性(步骤 5)
复制代码
# 主节点查看offset
127.0.0.1:6379> info replication
master_repl_offset:1000

# 从节点查看offset
127.0.0.1:6380> info replication
slave_repl_offset:1000

✅ 核心判断:主从节点 offset 完全一致,说明全量复制完成,数据同步正常。

5.3.4 全量复制的性能影响

全量复制是 "重量级" 操作,会消耗主节点和从节点的 CPU、内存、带宽资源,尤其是主节点发送 RDB 文件和缓冲区命令时,对性能影响较大:

(1)对主节点的性能影响(3 点)
  1. CPU 消耗:执行BGSAVE命令时,主节点需要 fork 子进程,fork 过程会消耗 CPU(fork 时间与主节点内存大小正相关,内存越大,fork 时间越长);
  2. 磁盘 IO 消耗:BGSAVE生成 RDB 文件,需要写入磁盘,磁盘 IO 繁忙时,会导致BGSAVE执行缓慢,甚至失败;
  3. 带宽消耗:发送 RDB 文件和缓冲区命令给从节点,尤其是 RDB 文件较大(如 10GB+)时,会占用大量带宽,若主节点有多个从节点同时执行全量复制,带宽会被占满,导致主节点无法正常处理业务请求。
(2)对从节点的性能影响(2 点)
  1. 磁盘 IO 消耗:接收 RDB 文件,写入临时文件,消耗磁盘 IO;
  2. 内存 + 阻塞影响:加载 RDB 文件时,从节点会阻塞,无法处理任何读请求(阻塞时间与 RDB 文件大小、从节点内存速度正相关),业务客户端会出现读超时。
(3)全量复制的优化方案
  1. 控制主节点内存大小:主节点内存建议不超过 16GB(最优),最大不超过 32GB,减少BGSAVE fork 时间和 RDB 文件大小;

  2. 主节点关闭持久化,从节点开启持久化:避免主节点BGSAVE生成 RDB 文件消耗性能(从节点开启持久化,保证数据安全);

  3. 避免多个从节点同时执行全量复制:新增从节点时,先让其同步一个已同步完成的从节点(如树形拓扑的中间层从节点),再切换到同步主节点,避免直接同步主节点,减少主节点带宽压力;

  4. 开启无磁盘同步(Redis 2.8 + 支持):主节点生成 RDB 文件时,不写入磁盘,直接通过网络发送给从节点,减少主节点磁盘 IO 消耗,配置如下:

    复制代码
    # 主节点配置文件(redis.conf)
    repl-diskless-sync yes  # 开启无磁盘同步
    repl-diskless-sync-delay 5  # 延迟5秒发送,等待从节点准备就绪
  5. 合理设置复制缓冲区大小:调大repl_backlog_size(如 64MB+),减少部分复制触发失败,从而减少全量复制的频率;

  6. 选择合适的时间执行全量复制:新增从节点、主从断连后重新同步等场景,尽量在业务低峰期(如凌晨)执行,减少对业务的影响。

5.4 数据同步阶段(核心阶段)------ 部分复制(增量同步)

部分复制是 "轻量级" 同步方式,适用于 "主从节点短暂断连(如网络闪断),重新连接后" 的场景,核心是 "只同步断连期间主节点执行的写命令",无需同步所有数据,大幅节省资源、减少延迟,是主从复制中最常用的同步方式(全量复制仅在首次同步时触发)。

5.4.1 部分复制的通俗类比(老师 - 助教)

助教在听课过程中,短暂走神(主从断连),错过了老师讲的 3 个知识点(主节点执行的 3 条写命令),走神结束后,助教不需要让老师重新讲所有内容(全量复制),只需要让老师把自己错过的 3 个知识点(断连期间的写命令)重新讲一遍(部分复制),抄到笔记本上,就可以和老师的内容保持一致。

5.4.2 部分复制的核心前提

部分复制能触发的核心是 "主节点记录了断连期间的写命令,从节点知道自己错过的命令范围",需要满足 3 个前提,否则会触发全量复制:

  1. 主从节点重新连接后,从节点的master_replid与主节点的master_replid一致(说明从节点同步的是当前主节点的数据集,没有切换过主节点);
  2. 从节点的slave_repl_offset在主节点复制缓冲区(repl_backlog)的可用范围内(主节点缓冲区中保存了从节点 offset 之后的所有写命令,可补发);
  3. 主从节点都开启了部分复制功能(Redis 2.8 + 默认开启,无需额外配置,旧版本不支持部分复制,只能用全量复制)。
5.4.3 部分复制的 5 个详细步骤

结合实战场景(主从节点正常同步,从节点 6380 断连 10 秒,重新连接后触发部分复制):

步骤 通俗类比 主节点操作(技术细节) 从节点操作(技术细节) 实战日志验证(核心日志)
步骤 1:主从节点短暂断连 助教走神,与老师断开联系(听不到老师讲课) 1. 主节点检测到与从节点的 TCP 连接断开,标记该从节点为 "offline";2. 主节点继续执行写命令,将所有写命令(断连期间)记录到复制缓冲区(repl_backlog)中;3. 主节点保持自身的master_replid和master_repl_offset不变 1. 从节点检测到与主节点的连接断开,标记master_link_status=down;2. 从节点停止接收主节点的写命令,保持自身的slave_repl_offset和master_replid不变;3. 从节点每隔 1 秒重试连接主节点 主节点日志:Replica 127.0.0.1:6380 is offline;从节点日志:Connection with master lost
步骤 2:从节点重新连接主节点 助教走神结束,重新找到老师,恢复联系 主节点接收从节点的重新连接请求,验证密码(若有),建立新的 TCP 连接 从节点发起重新连接请求,发送自身的master_replid和slave_repl_offset(告知主节点 "我之前同步到了 offset=1000,现在需要继续同步") 主节点日志:Accepted repl connection from 127.0.0.1:45679;从节点日志:Reconnecting to MASTER 127.0.0.1:6379
步骤 3:从节点发起部分复制请求 助教对老师说 "我之前听到了 offset=1000,麻烦把 1000 之后的内容(知识点)重新讲一遍" 无(等待从节点请求) 从节点发送PSYNC 主节点replid 1000命令(replid 是主节点的 replid,1000 是自身的 offset),请求同步 offset=1000 之后的命令 从节点日志:Sending PSYNC request to master;主节点日志:Replica asks for PSYNC
步骤 4:主节点校验,发送缓冲区命令 老师确认助教的 replid(是自己的学生),确认 offset=1000 之后有内容(缓冲区中有),就把这些内容重新讲一遍 1. 主节点校验从节点发送的 replid,与自身 replid 一致;2. 主节点校验从节点的 offset(1000),确认在复制缓冲区的可用范围内;3. 主节点从复制缓冲区中,提取 offset=1000 之后的所有写命令,按顺序发送给从节点;4. 发送完成后,主节点更新从节点的状态为 "online" 1. 从节点接收主节点发送的写命令,按顺序执行每一条命令;2. 每执行一条命令,从节点更新自身的slave_repl_offset,确保与主节点的 offset 一致;3. 执行完成后,从节点的数据集与主节点完全一致 主节点日志:Partial resync accepted by replica;Sending buffered commands to replica;从节点日志:Partial resync from master accepted
步骤 5:部分复制完成,恢复实时同步 助教抄完错过的知识点,重新开始实时抄录老师新讲的内容 主节点后续执行的所有写命令,都会实时发送给从节点 从节点标记master_link_status=up,持续接收主节点的写命令,实时执行,维持数据一致 主节点日志:Replica 127.0.0.1:6380 is online;从节点日志:MASTER <-> REPLICA sync: Finished with success
5.4.4 部分复制的实战验证

我们通过实战操作,模拟主从断连、重新连接,验证部分复制的触发和执行:

步骤 1:模拟主从断连(断开从节点与主节点的连接)
复制代码
# 找到从节点6380与主节点6379的TCP连接(从节点的客户端端口)
netstat -nlpt | grep 6379  # 查看主节点的连接,找到从节点的端口(如45678)
# 终止该TCP连接(模拟断连)
kill -9 连接对应的进程ID  # 或用iptables临时阻断端口,模拟网络闪断
步骤 2:主节点执行写命令(断连期间,生成需要补发的命令)
复制代码
# 连接主节点6379
redis-cli -p 6379 -a 123456
# 执行3条写命令(断连期间的命令,会记录到复制缓冲区)
127.0.0.1:6379> set a 10
OK
127.0.0.1:6379> set b 20
OK
127.0.0.1:6379> set c 30
OK
# 查看主节点offset(此时offset=1003,比断连前多3)
127.0.0.1:6379> info replication
master_repl_offset:1003
步骤 3:重新连接主从节点,验证部分复制
复制代码
# 重启从节点6380(重新连接主节点)
redis-cli -p 6380 -a 123456 shutdown
redis-server /usr/local/redis/conf/redis-slave-6380.conf

# 查看从节点日志,确认触发部分复制
cat /var/log/redis/redis-6380.log
# 核心日志(部分复制成功):
1235:M 10 Feb 2026 14:10:00.000 * Reconnecting to MASTER 127.0.0.1:6379
1235:M 10 Feb 2026 14:10:00.002 * Successfully authenticated with MASTER
1235:M 10 Feb 2026 14:10:00.003 * Partial resync from master accepted: offset 1000, master_replid 2fbd35a8b8401b22eb92ff49ad5e42250b3e7a06
1235:M 10 Feb 2026 14:10:00.004 * MASTER <-> REPLICA sync: Finished with success

# 验证从节点数据(是否同步了断连期间的3条命令)
redis-cli -p 6380 -a 123456
127.0.0.1:6380> get a
"10"
127.0.0.1:6380> get b
"20"
127.0.0.1:6380> get c
"30"  # 同步成功,触发部分复制

# 验证主从节点offset一致
127.0.0.1:6379> info replication
master_repl_offset:1003
127.0.0.1:6380> info replication
slave_repl_offset:1003  # 一致,部分复制完成

✅ 核心判断:从节点日志出现 "Partial resync accepted",主从 offset 一致,断连期间的命令同步成功,说明部分复制触发成功。

5.4.5 部分复制的优化方案
  1. 调大复制缓冲区大小(repl_backlog_size):缓冲区越大,能保存的写命令越多,主从断连的时间可以更长,避免断连时间过长导致 offset 超出缓冲区范围,触发全量复制;✅ 配置建议:根据主节点写并发调整,写并发越高,缓冲区设越大,一般 64MB 可满足绝大多数场景,写并发极高(每秒 10 万 QPS)设为 128MB+;
  2. 优化网络稳定性:减少主从节点之间的网络闪断(如部署在同一机房、检查网络设备),缩短断连时间,降低部分复制的触发频率,同时避免断连时间过长导致全量复制。
5.4.6 部分复制与全量复制的对比
对比维度 全量复制 部分复制
触发条件 1. 从节点首次同步;2. 从节点 replid 与主节点不一致;3. 从节点 offset 超出主节点缓冲区范围 1. 主从节点短暂断连后重新连接;2. 从节点 replid 与主节点一致;3. 从节点 offset 在主节点缓冲区范围内
同步内容 主节点所有数据(RDB 文件)+ 同步期间的缓冲区命令 主从断连期间主节点执行的写命令(仅缺失的命令)
资源消耗 高(CPU、内存、带宽、磁盘 IO 消耗大) 低(仅消耗少量带宽,无 CPU、磁盘 IO 大量消耗)
同步延迟 高(取决于 RDB 文件大小、网络带宽,可能几秒到几分钟) 低(取决于断连期间的命令数量,一般毫秒级)
适用场景 首次同步、主从断连时间过长、replid 不一致 主从短暂断连(网络闪断)后重新连接
Redis 版本支持 所有版本 2.8 + 版本(默认开启)

5.5 实时同步阶段(维持阶段)------ 心跳检测 + 命令传播

数据同步阶段(全量 / 部分)完成后,主从复制进入 "实时同步阶段",核心是 "主节点实时发送写命令,从节点实时执行,同时主从节点通过心跳检测维持连接",确保主从数据实时一致,这是主从复制长期维持的关键阶段。

5.5.1 实时同步阶段的两个核心任务(必记)

实时同步阶段有两个核心任务,相辅相成,缺一不可:① 命令传播(主节点实时发送写命令,从节点实时执行);② 心跳检测(主从节点互相确认在线状态,确保连接正常)。

5.5.2 任务 1:命令传播(实时同步写命令,核心)
(1)通俗类比(老师 - 助教)

助教抄完所有课件后,老师后续讲的每一个新知识点(主节点执行的每一条写命令),都会实时告诉助教,助教实时抄录到自己的笔记本上(从节点实时执行命令),确保笔记本上的内容和老师完全一致,没有延迟。

(2)技术细节
  1. 主节点命令传播操作:
    • 主节点执行任何一条写命令(set、del、hset、incr 等)后,都会立即将该命令发送给所有已连接的从节点(online 状态);
    • 主节点发送命令时,会按顺序发送,确保从节点执行命令的顺序与主节点一致(避免数据不一致);
    • 主节点发送命令后,会更新自身的master_repl_offset(每执行一条写命令,offset+1);
    • 主节点不会等待从节点的执行响应,采用 "异步传播" 方式(发送命令后,立即处理下一条业务命令),提高主节点的写请求处理效率。
  2. 从节点命令传播操作:
    • 从节点持续接收主节点发送的写命令,按顺序执行每一条命令(严格遵循主节点的命令顺序);
    • 从节点每执行一条命令,都会更新自身的slave_repl_offset,确保与主节点的master_repl_offset一致;
    • 从节点执行命令时,会阻塞吗?------ 不会,从节点执行写命令是异步的,不阻塞自身处理读请求(读请求可以正常执行,写命令后台顺序执行);
    • 从节点执行命令失败怎么办?------ 若执行命令失败(如命令格式错误),从节点会断开与主节点的连接,标记master_link_status=down,并持续重试连接,重新连接后触发全量 / 部分复制,恢复数据一致。
(3)实战验证:命令传播(实时同步)
复制代码
# 主节点(6379)执行写命令
127.0.0.1:6379> set d 40
OK
127.0.0.1:6379> incr e
(integer) 1
127.0.0.1:6379> hset user:3 id 3 name wangwu
(integer) 2

# 立即查看主节点offset
127.0.0.1:6379> info replication
master_repl_offset:1008  # 执行3条命令,offset从1003增加到1008

# 查看从节点(6380)数据和offset
127.0.0.1:6380> get d
"40"
127.0.0.1:6380> get e
"1"
127.0.0.1:6380> hgetall user:3
1) "id"
2) "3"
3) "name"
4) "wangwu"  # 实时同步成功

127.0.0.1:6380> info replication
slave_repl_offset:1008  # 与主节点offset一致

✅ 核心判断:主节点执行写命令后,从节点立即能查询到对应数据,主从 offset 一致,说明命令传播正常,实时同步生效。

5.5.3 任务 2:心跳检测(维持主从连接,必记)

主从节点进入实时同步阶段后,会通过 "心跳检测" 互相确认对方是否在线,避免连接断开后未发现,导致数据不一致,详细拆解:

(1)心跳检测的双向机制(主→从,从→主)

Redis 的心跳检测是 "双向的",主节点和从节点都会主动发送心跳包,确保连接正常:

① 从节点→主节点(心跳请求,核心)
  • 频率:默认每 1 秒发送一次(无需配置,Redis 默认);
  • 发送内容:REPLCONF ACK <offset>命令,其中offset是从节点当前的slave_repl_offset;
  • 核心作用:
  1. 告知主节点 "我还在线";
  2. 告知主节点 "我当前同步到了哪个 offset,是否有缺失的命令";
  3. 主节点收到该命令后,若发现从节点的 offset 落后于自身的 offset,会立即补发缺失的命令(确保从节点同步不落后)。
② 主节点→从节点(心跳响应,辅助)
  • 频率:默认每 10 秒发送一次(由repl-ping-replica-period参数控制);
  • 发送内容:PING命令(空命令,仅用于确认连接);
  • 核心作用:告知从节点 "我还在线",若从节点长时间(超过repl-timeout参数)未收到主节点的PING命令,会认为主节点宕机,标记master_link_status=down,并持续重试连接。
(2)核心配置参数(实战可调整)
复制代码
# 主节点配置文件(redis.conf),控制主节点→从节点的心跳频率
repl-ping-replica-period 10  # 主节点每10秒向从节点发送一次PING命令(默认10秒)

# 所有节点配置文件,控制心跳超时时间
repl-timeout 60  # 心跳超时时间60秒(默认60秒),若超过60秒未收到对方心跳,认为连接断开

✅ 配置建议:无需修改默认值,若主从网络不稳定,可将repl-ping-replica-period改为 5 秒(增加心跳频率),repl-timeout改为 30 秒(缩短超时时间),更快发现连接断开。

(3)实战验证:心跳检测
复制代码
# 查看主节点日志,确认主节点向从节点发送PING命令
cat /var/log/redis/redis-6379.log
# 核心日志:
1234:M 10 Feb 2026 14:20:00.000 * PING sent to replica 127.0.0.1:6380
1234:M 10 Feb 2026 14:20:10.000 * PING sent to replica 127.0.0.1:6380  # 每10秒一次

# 查看从节点日志,确认从节点向主节点发送REPLCONF ACK命令
cat /var/log/redis/redis-6380.log
# 核心日志:
1235:M 10 Feb 2026 14:20:00.000 * REPLCONF ACK 1008
1235:M 10 Feb 2026 14:20:01.000 * REPLCONF ACK 1008  # 每1秒一次

✅ 核心判断:主节点日志每 10 秒出现 "PING sent to replica",从节点日志每 1 秒出现 "REPLCONF ACK",说明心跳检测正常。

5.5.4 实时同步阶段的注意事项
  1. 主节点命令传播是异步的:主节点发送命令后,不会等待从节点执行完成,就会处理下一条命令,因此可能出现 "主节点执行完命令,从节点还未执行" 的毫秒级延迟,这是正常现象,无法完全避免;✅ 解决方案:对 "写后立即读" 的业务场景(如用户注册后立即查询),强制读主节点,避免读取到旧数据;
  2. 从节点心跳超时后的处理:从节点超过repl-timeout时间未收到主节点心跳,会断开连接,标记master_link_status=down,并持续重试连接,重新连接后触发全量 / 部分复制,无需人工干预;
  3. 主节点收到多个从节点的REPLCONF ACK命令后,会优先补发 offset 落后最多的从节点的命令,确保所有从节点都能同步到最新数据。

5.6 主从复制核心命令深度解析

前面的实战中,我们频繁使用slaveof、info replication等命令,这里详细拆解 3 个核心命令的用法、参数

5.6.1 命令 1:slaveof(配置主从关系,核心命令)
(1)命令格式(两种用法)
复制代码
# 用法1:设置从节点,同步指定主节点(IP+端口)
slaveof <masterip> <masterport>

# 用法2:取消从节点身份,晋升为独立主节点(断开与原主节点的连接)
slaveof no one
(2)参数解析
  • masterip:主节点的 IP 地址(本地部署用 127.0.0.1,跨机房部署用公网 IP);
  • masterport:主节点的 Redis 端口(如 6379);
  • no one:固定参数,表示 "取消从节点身份",无需修改。
(3)实战场景
  1. 部署从节点时,配置主从关系:

    复制代码
    # 从节点6380执行,同步主节点6379
    127.0.0.1:6380> slaveof 127.0.0.1 6379
    OK
  2. 主节点宕机后,将从节点晋升为主节点:

    复制代码
    # 从节点6380执行,取消从节点身份,晋升为主节点
    127.0.0.1:6380> slaveof no one
    OK
    # 关闭只读模式,处理写请求
    127.0.0.1:6380> config set slave-read-only no
    OK
  3. 从节点同步错误主节点后,重新配置正确主节点:

    复制代码
    # 从节点6380原本同步错误主节点6390,现在重新同步正确主节点6379
    127.0.0.1:6380> slaveof 127.0.0.1 6379
    OK
    # 注意:执行后,从节点会清空自身数据,重新同步6379的数据
  4. 树形拓扑中,配置下层从节点同步中间层从节点:

    复制代码
    # 下层从节点6381执行,同步中间层从节点6380
    127.0.0.1:6381> slaveof 127.0.0.1 6380
    OK
(4)注意事项
  1. 执行slaveof <masterip> <masterport>后,从节点会自动清空自身所有数据,无论之前是否有数据,都会被清空,避免数据混淆;
  2. 执行slaveof no one后,从节点会断开与原主节点的连接,晋升为独立主节点,自身的role变为master,master_link_status变为down(无主节点);
  3. 该命令是临时生效的,重启从节点后,会恢复到配置文件中slaveof参数指定的主节点,若要永久生效,需修改从节点配置文件中的slaveof参数。
5.6.2 命令 2:info replication(查看主从复制状态,排查故障核心)
(1)命令格式
复制代码
info replication
(2)命令作用

查看当前节点(主节点 / 从节点)的复制状态,包括节点角色、主从连接状态、offset、replid、从节点列表等核心信息,是排查主从复制故障的 "万能命令",无论什么故障,先执行该命令,再定位问题。

(3)主节点执行该命令的输出解析(核心字段,必记)
复制代码
127.0.0.1:6379> info replication
# Replication
role:master  # 节点角色:master(主节点)
connected_slaves:3  # 连接的从节点数量:3个(6380、6381、6382)
slave0:ip=127.0.0.1,port=6380,state=online,offset=1008,lag=0  # 第一个从节点:IP、端口、状态(online=在线)、offset、延迟(lag=0毫秒)
slave1:ip=127.0.0.1,port=6381,state=online,offset=1008,lag=0  # 第二个从节点
slave2:ip=127.0.0.1,port=6382,state=online,offset=1008,lag=0  # 第三个从节点
master_replid:2fbd35a8b8401b22eb92ff49ad5e42250b3e7a06  # 主节点复制ID(标识当前数据集)
master_replid2:0000000000000000000000000000000000000000  # 备用复制ID(用于部分复制失败时回退)
master_repl_offset:1008  # 主节点当前的复制偏移量(每执行一条写命令,offset+1)
repl_backlog_active:1  # 复制缓冲区是否开启:1=开启,0=关闭
repl_backlog_size:67108864  # 复制缓冲区大小:64MB
repl_backlog_first_byte_offset:1  # 复制缓冲区中第一条命令的offset
repl_backlog_histlen:1008  # 复制缓冲区中当前保存的命令长度

✅ 核心字段解读:

  • connected_slaves:确认主节点连接的从节点数量是否正确;
  • slavex:state:确认从节点状态是否为online(离线则为offline);
  • master_repl_offset:主节点当前的 offset,用于与从节点 offset 对比,确认同步是否正常;
  • repl_backlog_active:确认复制缓冲区是否开启,避免部分复制无法触发。
(4)从节点执行该命令的输出解析
复制代码
127.0.0.1:6380> info replication
# Replication
role:slave  # 节点角色:slave(从节点)
master_host:127.0.0.1  # 同步的主节点IP
master_port:6379  # 同步的主节点端口
master_link_status:up  # 与主节点的连接状态:up=正常,down=断开
master_last_io_seconds_ago:1  # 距离上次与主节点通信的时间(1秒,通信正常)
master_sync_in_progress:0  # 是否正在进行同步:0=未同步,1=正在同步(全量/部分)
slave_repl_offset:1008  # 从节点当前的offset,与主节点一致则同步正常
slave_priority:100  # 从节点优先级(值越小,故障转移时优先级越高)
master_replid:2fbd35a8b8401b22eb92ff49ad5e42250b3e7a06  # 主节点的复制ID,与主节点一致
master_replid2:0000000000000000000000000000000000000000  # 备用复制ID
slave_read_only:1  # 是否开启只读模式:1=开启,0=关闭
connected_slaves:0  # 该从节点没有下属从节点(树形拓扑的中间层从节点会有)
repl_backlog_active:1  # 复制缓冲区是否开启
repl_backlog_size:67108864  # 复制缓冲区大小
repl_backlog_first_byte_offset:1
repl_backlog_histlen:1008

✅ 核心字段解读(故障排查重点):

  • master_link_status:最核心字段,down表示连接断开,需排查网络、密码、主节点状态;
  • slave_repl_offset:与主节点master_repl_offset对比,不一致则同步异常;
  • master_sync_in_progress:1表示正在同步,若长时间为1,需查看日志,确认同步是否卡住;
  • master_replid:与主节点master_replid对比,不一致则会触发全量复制。
5.6.3 命令 3:PSYNC/SYNC(同步命令,底层命令,无需手动执行)
(1)命令作用

PSYNC和SYNC是主从复制底层用于 "请求同步、协商同步方式" 的命令,无需手动执行,从节点发起同步时会自动发送,其中PSYNC是 Redis 2.8 + 新增的命令,支持部分复制,SYNC是旧版本命令,仅支持全量复制。

(2)命令格式(底层自动发送,了解即可)
复制代码
# PSYNC命令(Redis 2.8+,支持全量/部分复制)
PSYNC <master_replid> <slave_repl_offset>

# SYNC命令(旧版本,仅支持全量复制)
SYNC
(3)命令解析
  • PSYNC ? -1:从节点首次同步时发送,?表示不知道主节点的 replid,-1表示 offset 为 - 1,请求全量复制;
  • PSYNC <replid> <offset>:从节点重新连接时发送,replid是主节点的 replid,offset是自身的 offset,请求部分复制;
  • 主节点收到PSYNC命令后,会根据 replid 和 offset,决定返回+FULLRESYNC(全量复制)或+CONTINUE(部分复制)。
(4)注意事项

无需手动执行该命令,从节点会自动发送,排查同步故障时,可通过日志查看该命令的发送和响应情况(如 "Partial resync accepted" 表示 PSYNC 请求部分复制成功)。

5.7 主从复制核心参数深度解析

前面的实战中,我们配置了多个参数(如slaveof、masterauth),这里详细拆解 6 个核心参数的作用、默认值、生产配置建议,确保大家能根据业务场景,配置出最优的主从复制参数,避免踩坑。

5.7.1 参数 1:slaveof(配置主从关系,核心参数)
(1)参数格式(配置文件中)
复制代码
slaveof <masterip> <masterport>
(2)参数作用

指定当前节点作为从节点,同步指定 IP 和端口的主节点,是主从复制的核心参数,与slaveof命令功能一致,但配置文件中配置是永久生效,命令行执行是临时生效。

(3)默认值

默认无配置(即节点默认角色为主节点,不主动同步任何节点);若未配置该参数,节点启动后role=master,connected_slaves=0。

(4)生产配置建议
  1. 一主一从架构(从节点):配置为 slaveof 主节点IP 主节点端口,本地部署示例:slaveof 127.0.0.1 6379;
  2. 一主多从架构(所有从节点):所有从节点统一配置为 slaveof 主节点IP 主节点端口,确保所有从节点同步同一个主节点,示例:6380、6381、6382 均配置 slaveof 127.0.0.1 6379;
  3. 树形拓扑架构(下层从节点):配置为 slaveof 中间层从节点IP 中间层从节点端口,示例:下层从节点 6381 配置 slaveof 127.0.0.1 6380(6380 为中间层从节点);
  4. 跨机房部署(从节点 / 下层从节点):配置为主节点 / 中间层从节点的公网 IP + 端口 ,示例:机房 B 的 6381 配置 slaveof 123.45.67.89 6380(123.45.67.89 为机房 A 中间层从节点公网 IP);
  5. 无需作为从节点的节点(独立主节点):不配置该参数,保持默认即可,避免误配置导致节点变为从节点。
(5)注意事项
  1. 配置文件中修改slaveof后,必须重启从节点才能生效 ;命令行执行slaveof命令是临时生效,重启节点后会恢复到配置文件中的设置(若想永久生效,需同步修改配置文件);
  2. 若从节点已配置slaveof并同步主节点,后续修改slaveof参数(如切换主节点),重启后从节点会清空自身所有数据,重新同步新的主节点,需提前备份从节点数据;
  3. 主节点无需配置slaveof参数(默认为主节点),若主节点误配置slaveof,会导致主节点变为从节点,自身写请求被禁止(只读),引发业务故障;
  4. 跨机房部署时,slaveof的 IP 必须是主节点 / 中间层从节点的公网 IP,且目标节点需开放对应端口(防火墙放行),否则从节点无法连接。

5.7.2 参数 2:masterauth(从节点验证主节点密码,核心参数)

(1)参数格式(配置文件中)
复制代码
masterauth <password>
(2)参数作用

当主节点(或中间层从节点)开启密码验证(配置requirepass <password>)时,从节点必须配置masterauth,并填写与主节点requirepass一致的密码,否则从节点无法通过主节点的身份验证,无法建立同步连接(日志会报密码错误)。简单说:masterauth是从节点 "登录" 主节点的密码,确保主从连接的安全性。

(3)默认值

默认值为空字符串(""),即不设置密码验证,若主节点未配置requirepass,从节点可无需配置masterauth。

(4)生产配置建议
  1. 所有从节点(无论哪种拓扑),必须配置masterauth ,且密码与主节点requirepass完全一致(主节点必须开启requirepass,禁止无密码部署);
  2. 密码建议设置复杂密码(字母 + 数字 + 特殊符号,长度≥8 位),避免简单密码被破解,示例:masterauth Redis@123456;
  3. 若主节点后续修改requirepass密码,所有从节点的masterauth必须同步修改(配置文件 + 重启),否则主从连接会断开,同步失败;
  4. 树形拓扑中,下层从节点的masterauth,需填写与主节点 一致的密码(而非中间层从节点的requirepass),因为中间层从节点转发主节点的同步命令时,会验证该密码;
  5. 多个从节点的masterauth必须保持一致(均与主节点密码一致),便于维护和扩容。
(5)注意事项
  1. masterauth仅需在从节点配置,主节点无需配置(主节点用requirepass设置自身密码,用于客户端和从节点登录);
  2. 密码不一致的后果:从节点反复重试连接主节点,日志持续输出Error: Authentication failed,无法建立同步连接,主从复制失败;
  3. 配置文件中修改masterauth后,必须重启从节点才能生效 ;命令行临时修改用config set masterauth <password>,重启后失效(需同步修改配置文件);
  4. 若主节点未配置requirepass(无密码),从节点配置masterauth也不会报错,但无实际意义(建议主节点强制开启密码验证)。

5.7.3 参数 3:slave-read-only(从节点只读模式,核心参数)

(1)参数格式(配置文件中)
复制代码
slave-read-only yes|no
(补充)Redis 6.0+ 新增参数(推荐使用)

Redis 6.0+ 将slave-read-only更名为replica-read-only,功能完全一致,仅参数名不同,推荐使用新参数(兼容性更好):

复制代码
replica-read-only yes|no
(2)参数作用

控制从节点是否开启 "只读模式":

  • 设为yes(开启):从节点仅允许执行读命令(如 get、hget、lrange),禁止执行任何写命令(如 set、del、hset),避免从节点数据被篡改;
  • 设为no(关闭):从节点允许执行写命令,但会导致主从数据不一致(主节点同步命令会覆盖从节点的写数据),仅在特定场景使用(如从节点晋升为主节点时)。
(3)默认值

Redis 2.8+ 默认值为yes(开启只读模式);Redis 6.0+ 中,slave-read-only和replica-read-only默认均为yes,若同时配置,replica-read-only生效。

(4)生产配置建议(强制开启)
  1. 所有从节点(无论哪种拓扑、是否跨机房),必须配置为yes(开启只读模式) ,禁止设置为no;
  2. 仅有的例外场景:主节点宕机后,将从节点晋升为主节点时,临时关闭只读模式(命令行执行config set slave-read-only no),让其处理写请求;待原主节点恢复后,再根据需求切换主从关系,重新开启只读模式;
  3. Redis 6.0+ 部署时,推荐使用新参数replica-read-only yes,示例:replica-read-only yes。
(5)注意事项
  1. 开启只读模式后,从节点仍允许执行flushall、flushdb等危险命令(若未限制),需额外配置禁止这些命令(如通过rename-command重命名命令);
  2. 即使开启只读模式,管理员通过命令行仍可执行写命令(需验证密码),但业务客户端禁止执行写命令,需通过权限控制限制业务客户端的操作;
  3. 若误将slave-read-only设为no,从节点执行写命令后,主节点同步的命令会覆盖该写数据,导致从节点数据 "丢失",引发业务查询异常(读旧数据 / 错误数据);
  4. Redis 6.0+ 中,若同时配置slave-read-only no和replica-read-only yes,最终生效的是replica-read-only yes(只读模式开启),需注意参数冲突。

5.7.4 参数 4:repl_backlog_size(复制缓冲区大小,优化参数)

(1)参数格式(配置文件中)
复制代码
repl_backlog_size <size>

(单位:字节,可直接写数字,如 67108864 表示 64MB)

(2)参数作用

设置主节点 "复制积压缓冲区"(repl_backlog)的大小,该缓冲区的核心作用是:

  • 保存主节点执行的写命令,供从节点短暂断连后重新连接时,补发缺失的命令(触发部分复制);
  • 避免从节点断连时间过长,缓冲区中的旧命令被覆盖,导致无法触发部分复制,只能触发全量复制(消耗大量资源)。

简单说:复制缓冲区越大,能保存的写命令越多,主从断连的 "最大允许时间" 越长(断连时间 = 缓冲区大小 / 每秒写命令总量)。

(3)默认值

Redis 默认值为1048576字节(即 1MB),该默认值过小,无法满足绝大多数生产场景(写并发稍高,1MB 缓冲区几秒就会被写满),必须手动修改。

(4)生产配置建议(分场景调整)

根据主节点写并发、部署场景(同机房 / 跨机房)调整,推荐值如下(直接套用):

  1. 同机房部署、写并发较低(每秒写 QPS≤1 万):设为 64MB(67108864),示例:repl_backlog_size 67108864;
  2. 同机房部署、写并发中等(每秒写 QPS 1-5 万):设为 128MB(134217728),示例:repl_backlog_size 134217728;
  3. 跨机房部署、写并发较低(每秒写 QPS≤1 万):设为 128MB(134217728),跨机房网络不稳定,需更大缓冲区;
  4. 跨机房部署、写并发中等(每秒写 QPS 1-5 万):设为 256MB(268435456),示例:repl_backlog_size 268435456;
  5. 写并发极高(每秒写 QPS≥5 万):设为 512MB(536870912),避免缓冲区快速被写满。
(5)注意事项(生产必避坑)
  1. 该参数仅需在主节点配置,从节点无需配置(从节点也有复制缓冲区,但无需手动设置,由 Redis 自动管理);
  2. 缓冲区大小并非越大越好:过大(如 1GB)会浪费主节点内存,过小则无法满足断连需求,需根据实际写并发调整;
  3. 配置文件中修改repl_backlog_size后,必须重启主节点才能生效 ;命令行临时修改用config set repl_backlog_size <size>,重启后失效;
  4. 若主节点有多个从节点,复制缓冲区是所有从节点共享的,无需为每个从节点单独配置;
  5. 结合repl_backlog_ttl参数(Redis 5.0+)使用,可实现缓冲区自动扩容 / 收缩(如repl_backlog_ttl 3600,缓冲区空闲 1 小时后自动收缩到默认大小)。

5.7.5 参数 5:repl-disable-tcp-nodelay(TCP_NODELAY 配置,优化参数)

(1)参数格式(配置文件中)
复制代码
repl-disable-tcp-nodelay yes|no
(2)参数作用

控制主节点向从节点发送同步命令(命令传播、全量复制的 RDB 文件除外)时,是否启用 "Nagle 算法":

  • Nagle 算法(repl-disable-tcp-nodelay yes):合并多个小数据包为一个大数据包发送,节省网络带宽,但会增加命令传播延迟(约 40ms 左右);
  • 禁用 Nagle 算法(repl-disable-tcp-nodelay no):不合并数据包,每个写命令单独发送,延迟极低(毫秒级),但会消耗更多网络带宽。

核心权衡:延迟 vs 带宽,根据部署场景选择开启 / 关闭。

(3)默认值

Redis 默认值为no(禁用 Nagle 算法),即优先保证低延迟,适合同机房部署场景。

(4)生产配置建议(分场景选择)
  1. 同机房部署(带宽充足、延迟要求高):保持默认值no,禁用 Nagle 算法,减少命令传播延迟(毫秒级),确保主从数据实时一致;
  2. 跨机房部署(带宽昂贵、延迟可接受):设为yes,启用 Nagle 算法,合并数据包,节省跨机房带宽(跨机房带宽成本高,优先节省带宽);
  3. 树形拓扑架构:
    • 主节点→中间层从节点(同机房):repl-disable-tcp-nodelay no(低延迟);
    • 中间层从节点→下层从节点(跨机房):repl-disable-tcp-nodelay yes(省带宽)。
(5)注意事项(生产必避坑)
  1. 该参数仅需在主节点配置(中间层从节点作为 "二级主节点",向下层从节点发送命令时,也需配置该参数);
  2. 跨机房部署若误设为no,会导致跨机房带宽被大量小数据包占用,带宽成本飙升,甚至出现带宽拥堵,导致同步延迟过高;
  3. 同机房部署若误设为yes,会导致命令传播延迟增加(40ms 左右),对于 "写后立即读" 的场景,会频繁出现读取旧数据的问题;
  4. 修改该参数后,必须重启主节点 / 中间层从节点才能生效 ;命令行临时修改用config set repl-disable-tcp-nodelay yes,重启后失效。

5.7.6 参数 6:repl-ping-replica-period(主节点心跳频率,维持连接参数)

(1)参数格式(配置文件中)
复制代码
repl-ping-replica-period <seconds>

(单位:秒,填写整数)

(2)参数作用

设置主节点向所有已连接的从节点(online 状态)发送PING命令的频率,用于心跳检测:

  • 主节点定期发送PING命令,告知从节点 "自身在线";
  • 从节点若在repl-timeout时间内未收到主节点的PING命令,会认为主节点宕机,标记master_link_status=down,并持续重试连接。

简单说:该参数控制主节点向从节点的 "心跳频率",频率越高,越能快速发现主节点宕机。

(3)默认值

Redis 默认值为10秒,即主节点每 10 秒向从节点发送一次PING命令。

(4)生产配置建议(无需修改默认,特殊场景调整)
  1. 绝大多数场景(同机房、网络稳定):保持默认值10秒,既能快速发现主节点宕机,又不会增加主节点和网络压力;
  2. 网络不稳定场景(跨机房、无线网络):改为5秒,增加心跳频率,更快发现主从连接断开,减少数据同步延迟;
  3. 业务对可用性要求极高场景(金融、支付):改为3秒,进一步缩短心跳间隔,确保主节点宕机后能快速被发现,便于人工干预切换主从。
(5)注意事项(生产必避坑)
  1. 该参数仅需在主节点配置,从节点无需配置;
  2. 频率设置过低(如 1 秒):会导致主节点频繁发送PING命令,增加主节点 CPU 和网络压力,不推荐;
  3. 频率设置过高(如 30 秒):会导致主节点宕机后,从节点长时间未发现,同步延迟过大,甚至触发不必要的全量复制;
  4. 修改该参数后,无需重启主节点 ,命令行临时修改用config set repl-ping-replica-period 5,立即生效(配置文件修改后仍需重启才能永久生效)。

5.7.7 参数 7:repl-timeout(心跳超时时间,维持连接参数)

(1)参数格式(配置文件中)
复制代码
repl-timeout <seconds>

(单位:秒,填写整数)

(2)参数作用

设置主从复制的 "心跳超时时间",用于判断主从连接是否正常,触发条件:

  1. 从节点:在repl-timeout时间内,未收到主节点的PING命令(心跳),或未收到主节点发送的同步命令(命令传播、全量 / 部分复制的命令),则认为主节点宕机,标记master_link_status=down,并持续重试连接;
  2. 主节点:在repl-timeout时间内,未收到从节点的REPLCONF ACK命令(从节点的心跳),则认为该从节点离线,标记state=offline,停止向其发送同步命令。

简单说:该参数是主从连接的 "超时阈值",超过这个时间无通信,就认为连接断开。

(3)默认值

Redis 默认值为60秒,即主从节点超过 60 秒无通信,就认为连接断开。

(4)生产配置建议(分场景调整)
  1. 同机房部署、网络稳定:保持默认值60秒,避免网络波动导致误判连接断开;
  2. 网络不稳定场景(跨机房、无线网络):改为30秒,缩短超时时间,更快发现连接断开,减少同步延迟;
  3. 结合repl-ping-replica-period配置:建议repl-timeout是repl-ping-replica-period的 3-6 倍(如repl-ping-replica-period=5秒,repl-timeout=30秒),避免因网络波动导致误判。
(5)注意事项(生产必避坑)
  1. 该参数所有节点都需配置(主节点和从节点),建议所有节点配置一致,避免出现判断不一致的情况;
  2. 超时时间设置过短(如 10 秒):容易因网络波动(如毫秒级卡顿)导致误判连接断开,从节点频繁重试连接,甚至触发全量复制,影响业务;
  3. 超时时间设置过长(如 120 秒):主节点宕机后,从节点长时间未发现,无法及时重试连接,同步延迟过大,业务读请求可能读取到旧数据;
  4. 修改该参数后,无需重启节点 ,命令行临时修改用config set repl-timeout 30,立即生效(配置文件修改后需重启才能永久生效);
  5. 连接断开后,从节点会每隔 1 秒重试连接主节点,直到重新连接成功,无需人工干预。

5.7.8 核心参数总结

参数名称 默认值 核心作用 生产推荐值(分场景) 配置节点
slaveof 无配置 配置从节点同步的主节点(IP + 端口) 一主一从 / 多从:slaveof 主 IP 6379;树形下层:slaveof 中间层 IP 中间层端口;跨机房:公网 IP 从节点 / 下层从节点
masterauth 空字符串 从节点验证主节点密码 与主节点 requirepass 一致(如 masterauth Redis@123456) 从节点 / 下层从节点
slave-read-only(6.0 + 用 replica-read-only) yes 控制从节点是否开启只读模式 所有从节点:yes(开启);从节点晋升主节点时临时设 no 从节点 / 下层从节点
repl_backlog_size 1MB 设置主节点复制缓冲区大小,支持部分复制 同机房低并发:64MB;同机房中并发 / 跨机房低并发:128MB;跨机房中并发:256MB+ 主节点 / 中间层从节点
repl-disable-tcp-nodelay no 控制主节点是否启用 Nagle 算法(延迟 vs 带宽) 同机房:no;跨机房:yes 主节点 / 中间层从节点
repl-ping-replica-period 10 秒 主节点向从节点发送 PING 命令的频率(心跳) 稳定场景:10 秒;不稳定 / 高可用场景:5 秒 / 3 秒 主节点 / 中间层从节点
repl-timeout 60 秒 主从心跳超时时间,判断连接是否断开 稳定场景:60 秒;不稳定场景:30 秒(建议是 ping 频率的 3-6 倍) 所有节点

5.8 主从复制底层原理常见问题

前面讲解了主从复制的流程、命令、参数,实际生产中,主从复制难免出现故障(如同步失败、延迟过高、连接断开),这里结合底层原理,拆解 6 个最常见的故障,每个故障都包含 "故障现象、故障原因、排查步骤、解决方案",全程实战化,可直接用于生产故障排查。

(1)故障现象(必看)
  • 从节点执行info replication,显示master_link_status=down(连接断开);
  • 从节点日志持续输出Connecting to MASTER 主节点IP:端口,但始终无法连接,或提示Authentication failed;
  • 主节点执行info replication,connected_slaves数量未包含该从节点,或显示该从节点state=offline;
  • 从节点无法同步主节点数据,业务读请求若走该从节点,可能读取到旧数据(若有)或报错。
(2)故障原因(按概率排序,必查)
  1. 密码不一致:主节点requirepass与从节点masterauth密码不一致(最常见);
  2. 网络问题:主从节点之间网络不通(防火墙未放行端口、IP 错误、网络中断);
  3. 主节点未启动:主节点宕机、未启动,或主节点端口错误(如误写 6380 为 6379);
  4. slaveof配置错误:从节点slaveof参数配置的主节点 IP / 端口错误(如跨机房用内网 IP);
  5. 主节点拒绝连接:主节点配置bind参数,仅允许特定 IP 访问,从节点 IP 未在允许范围内;
  6. 权限问题:从节点数据目录权限不足,无法创建临时文件(接收 RDB 文件时),导致连接失败。
(3)排查步骤(按简单到复杂,实战可直接套用)

步骤 1:检查主节点状态(最基础)

复制代码
# 查看主节点是否启动(CentOS)
ps -ef | grep redis-server | grep 主节点端口(如6379)
# 若未启动,启动主节点
redis-server /usr/local/redis/conf/redis.conf

# 查看主节点端口是否可访问
netstat -nlpt | grep 主节点端口(如6379)

步骤 2:检查从节点slaveof和masterauth配置(最常见)

复制代码
# 连接从节点,查看配置
redis-cli -p 从节点端口 -a 密码
127.0.0.1:从节点端口> config get slaveof
1) "slaveof"
2) "主节点IP 主节点端口"  # 确认IP和端口是否正确

127.0.0.1:从节点端口> config get masterauth
1) "masterauth"
2) "从节点密码"  # 记录密码,与主节点requirepass对比

# 连接主节点,查看requirepass配置
redis-cli -p 主节点端口 -a 主节点密码
127.0.0.1:主节点端口> config get requirepass
1) "requirepass"
2) "主节点密码"  # 与从节点masterauth对比,是否一致

步骤 3:检查主从节点网络连通性(防火墙、IP)

复制代码
# 在从节点上,ping主节点IP,检查网络是否连通
ping 主节点IP
# 若ping不通,排查网络中断、IP错误

# 在从节点上,测试主节点端口是否可访问(telnet)
telnet 主节点IP 主节点端口
# 若提示"Connection refused",说明端口未开放,检查防火墙

# 检查防火墙配置(CentOS,开放主节点端口)
firewall-cmd --list-ports  # 查看已开放端口
# 若主节点端口未开放,开放端口(永久生效)
firewall-cmd --add-port=主节点端口/tcp --permanent
firewall-cmd --reload

步骤 4:检查主节点bind参数(是否限制 IP 访问)

复制代码
# 连接主节点,查看bind配置
127.0.0.1:主节点端口> config get bind
1) "bind"
2) "127.0.0.1"  # 仅允许本地访问,从节点(非本地)无法连接

步骤 5:检查从节点数据目录权限(少见,但需排查)

复制代码
# 查看从节点数据目录权限(CentOS)
ls -ld /var/lib/redis/从节点端口(如6380)
# 若权限不足(非777),修改权限
chmod 777 /var/lib/redis/从节点端口
(4)解决方案(对应故障原因,直接落地)
  1. 密码不一致:修改从节点masterauth,与主节点requirepass完全一致,重启从节点;或临时修改从节点密码(config set masterauth 主节点密码),同步修改配置文件;
  2. 网络问题:修复网络(重启路由器、交换机);防火墙开放主节点端口;确认主节点 IP 正确(跨机房用公网 IP);
  3. 主节点未启动:启动主节点,确认主节点配置文件正确(无语法错误);
  4. slaveof配置错误:修改从节点slaveof参数(配置文件 + 重启),填写正确的主节点 IP 和端口;
  5. 主节点bind限制:修改主节点bind参数为0.0.0.0(允许所有 IP 访问,生产不推荐),或添加从节点 IP 到bind列表(推荐),重启主节点;
  6. 权限不足:修改从节点数据目录权限为 777,重启从节点,重新建立连接。
5.8.2 故障 2:主从同步延迟过高(slave_repl_offset 与 master_repl_offset 差距大)
(1)故障现象(必看)
  • 主节点执行info replication,master_repl_offset值较大;从节点执行info replication,slave_repl_offset值较小,两者差距持续增大(如差距超过 1000);
  • 业务读请求走从节点时,读取到旧数据(如主节点已更新数据,从节点仍显示旧值);
  • 从节点日志持续输出MASTER <-> REPLICA sync: Receiving commands,但slave_repl_offset增长缓慢;
  • 极端情况下,延迟超过repl-timeout,导致主从连接断开,重新触发全量复制。
(2)故障原因(结合原理,必查)
  1. 主节点写并发过高:主节点每秒写 QPS 过高(如超过 10 万),写命令生成速度超过从节点执行速度,导致延迟累积;
  2. 从节点性能不足:从节点 CPU、内存、磁盘 IO 不足(如 CPU 100%、内存溢出),无法及时执行主节点发送的写命令;
  3. 网络延迟过高:主从节点跨机房部署,网络延迟过大(如超过 100ms),命令传播延迟累积;或网络带宽不足,主节点发送命令速度受限;
  4. 全量复制未完成:从节点正在执行全量复制(加载 RDB 文件),加载期间无法执行写命令,导致延迟剧增;
  5. 复制缓冲区过小:repl_backlog_size过小,主节点写命令快速覆盖缓冲区,导致从节点频繁触发全量复制,进一步增加延迟;
  6. 从节点数量过多:一主多从架构中,从节点数量超过 5 个,主节点同步压力过大,命令传播延迟增加;
  7. 从节点开启持久化消耗性能:从节点同时开启 RDB 和 AOF 持久化,磁盘 IO 繁忙,影响写命令执行速度。
(3)排查步骤(实战可直接套用)

步骤 1:检查主节点写并发和负载

复制代码
# 连接主节点,查看写命令执行情况(临时开启慢查询,捕捉写命令)
127.0.0.1:6379> config set slowlog-log-slower-than 0  # 记录所有命令
127.0.0.1:6379> slowlog get 10  # 查看最近10条命令,确认是否有大量写命令

# 查看主节点CPU、内存负载
127.0.0.1:6379> info stats
used_cpu_sys:10.5  # 系统CPU使用情况
used_cpu_user:25.3  # 用户CPU使用情况(过高说明负载大)
used_memory_human:8.00G  # 内存使用情况

# 查看主节点写QPS(approximate_keys_per_second)
127.0.0.1:6379> info stats | grep keys_per_second

步骤 2:检查从节点负载和执行速度

复制代码
# 连接从节点,查看CPU、内存负载
127.0.0.1:从节点端口> info stats
used_cpu_sys:15.2  # 若CPU过高(如超过80%),说明性能不足
used_cpu_user:30.5
used_memory_human:8.00G  # 内存是否溢出

# 查看从节点是否正在执行全量复制
127.0.0.1:从节点端口> info replication
master_sync_in_progress:1  # 1=正在同步(全量/部分),0=未同步

# 查看从节点磁盘IO情况(CentOS)
iostat -x 1 3  # 查看磁盘IO使用率,若%util接近100%,说明磁盘IO繁忙

步骤 3:检查主从网络延迟和带宽

复制代码
# 在从节点上,测试与主节点的网络延迟(ping)
ping 主节点IP -c 10  # 查看平均延迟,若超过50ms,说明延迟过高

# 测试主从节点之间的带宽(scp命令,传输文件测试)
# 在主节点创建100MB测试文件
dd if=/dev/zero of=test.txt bs=100M count=1
# 在从节点上下载,查看传输速度
scp 主节点IP:/root/test.txt /root/  # 若速度过低,说明带宽不足

步骤 4:检查复制缓冲区和从节点数量

复制代码
# 主节点查看复制缓冲区使用情况
127.0.0.1:6379> info replication
repl_backlog_size:67108864  # 缓冲区大小
repl_backlog_histlen:67108864  # 已使用大小(若等于缓冲区大小,说明已写满)

# 查看主节点连接的从节点数量
127.0.0.1:6379> info replication | grep connected_slaves
connected_slaves:6  # 超过5个,同步压力过大
(4)解决方案
  1. 主节点写并发过高:
    • 拆分主节点:将不同业务的数据拆分到多个主节点,分担写压力;
    • 控制写并发峰值:通过业务限流,避免写请求集中爆发(如每秒写 QPS 控制在 5 万以内);
    • 优化写命令:合并批量写命令(如用 mset 代替多次 set),减少命令数量。
  2. 从节点性能不足:
    • 升级从节点硬件(增加 CPU 核心、扩大内存、更换 SSD 磁盘);
    • 关闭从节点不必要的功能(如关闭 Redis 集群模式、禁用无用的日志);
    • 新增从节点,分担读压力,减少单个从节点的命令执行压力。
  3. 网络延迟 / 带宽不足:
    • 同机房部署:将主从节点部署在同一机房,降低网络延迟;
    • 跨机房优化:开启repl-disable-tcp-nodelay yes,合并数据包,节省带宽;升级跨机房带宽;
    • 树形拓扑:采用主 - 从 - 从架构,减少跨机房同步的数据量。
  4. 全量复制未完成:
    • 选择业务低峰期执行全量复制(如凌晨);
    • 优化全量复制:主节点关闭持久化,从节点开启持久化;开启无磁盘同步(repl-diskless-sync yes);
    • 调大复制缓冲区,避免频繁触发全量复制。
  5. 复制缓冲区过小:修改主节点repl_backlog_size参数(如从 64MB 改为 128MB),重启主节点,避免缓冲区快速写满。
  6. 从节点数量过多:
    • 减少从节点数量(控制在 5 个以内);
    • 采用树形拓扑架构,增加中间层从节点,分担主节点同步压力。
  7. 从节点持久化消耗性能:
    • 优化 AOF 配置:appendfsync everysec(每秒同步一次,平衡性能和安全性);
    • 关闭 RDB 持久化(仅保留 AOF),减少磁盘 IO 消耗;
    • 定时在业务低峰期执行bgsave,生成 RDB 备份,避免实时 RDB 消耗性能。
5.8.3 故障 3:全量复制频繁触发(日志频繁出现 Full resync)
(1)故障现象(必看)
  • 从节点日志频繁输出Full resync requested by replica、Starting BGSAVE for SYNC,每几分钟或几小时触发一次全量复制;
  • 主节点 CPU、磁盘 IO 频繁飙升(BGSAVE 生成 RDB 文件),带宽被大量占用,影响主节点写请求处理;
  • 从节点频繁加载 RDB 文件,加载期间无法处理读请求,业务报错或读取旧数据;
  • 主从同步频繁中断,slave_repl_offset反复重置为 0。
(2)故障原因(结合全量复制触发条件,必查)
  1. 复制缓冲区过小:repl_backlog_size过小,主从节点短暂断连(如网络闪断)后,从节点slave_repl_offset超出缓冲区范围,触发全量复制;
  2. 主节点重启频繁:主节点因故障、维护频繁重启,重启后生成新的master_replid,从节点master_replid与主节点不一致,触发全量复制;
  3. 主从连接不稳定:网络波动频繁,主从连接反复断开、重新连接,每次重新连接都触发全量复制;
  4. 从节点频繁重启:从节点因性能不足、故障频繁重启,重启后作为新节点,首次同步主节点,触发全量复制;
  5. 主节点执行debug reload命令:该命令会重启主节点(软重启),生成新的master_replid,触发所有从节点全量复制;
  6. Redis 版本不一致:主从节点 Redis 版本不同(如主节点 6.2,从节点 5.0),同步过程中出现兼容性问题,导致全量复制反复触发。
(3)排查步骤

步骤 1:查看从节点日志,确认全量复制触发频率和原因

复制代码
# 查看从节点日志,过滤全量复制相关信息(CentOS)
grep "Full resync" /var/log/redis/redis-从节点端口.log
# 输出示例:1235:M 10 Feb 2026 15:00:00.000 * Full resync from master: 2fbd35a8b8401b22eb92ff49ad5e42250b3e7a06:0
# 若频繁出现,说明全量复制频繁触发

# 查看日志中是否有连接断开信息
grep "Connection with master lost" /var/log/redis/redis-从节点端口.log

步骤 2:检查主节点复制缓冲区使用情况

复制代码
# 主节点查看复制缓冲区大小和已使用情况
127.0.0.1:6379> info replication
repl_backlog_size:67108864  # 缓冲区大小(默认1MB需修改)
repl_backlog_histlen:67108864  # 已使用大小,若等于缓冲区大小,说明已写满
repl_backlog_first_byte_offset:1000  # 缓冲区第一条命令的offset

步骤 3:检查主从节点重启记录

复制代码
# 查看主节点重启记录(CentOS)
journalctl -u redis-server | grep "restart"  # 若频繁出现restart,说明主节点频繁重启

# 查看从节点重启记录
journalctl -u redis-server@从节点端口 | grep "restart"

步骤 4:检查主从节点网络稳定性和 Redis 版本

复制代码
# 查看主从节点网络波动情况(CentOS)
ping 主节点IP -c 100 | grep "packet loss"  # 查看丢包率,丢包率过高说明网络不稳定

# 查看主从节点Redis版本
redis-server -v  # 主节点版本
redis-cli -p 从节点端口 -a 密码 info server | grep redis_version  # 从节点版本
(4)解决方案
  1. 复制缓冲区过小:调大主节点repl_backlog_size参数(如从 64MB 改为 128MB/256MB),重启主节点;结合repl_backlog_ttl参数,实现缓冲区自动扩容 / 收缩;
  2. 主节点重启频繁:
    • 排查主节点重启原因(如内存溢出、配置错误、硬件故障),修复故障,避免频繁重启;
    • 主节点关闭持久化,减少BGSAVE和AOF触发的重启;
    • 采用主从切换,将频繁重启的主节点改为从节点,更换新的主节点。
  3. 主从连接不稳定:
    • 优化网络环境(检查网络设备、减少网络拥堵);
    • 调整repl-timeout参数(如改为 30 秒),避免网络波动导致误判连接断开;
    • 同机房部署,减少跨机房网络波动的影响;
    • 开启repl-disable-tcp-nodelay no(同机房),减少命令传播延迟,降低连接断开概率。
  4. 从节点频繁重启:
    • 排查从节点重启原因(性能不足、内存溢出、磁盘 IO 繁忙),升级硬件或优化配置;
    • 减少从节点负载(新增从节点,分担读压力);
    • 从节点关闭不必要的功能(如关闭持久化,仅主节点开启,不推荐,建议从节点开启 AOF)。
  5. 主节点误执行debug reload:禁止在生产环境执行debug reload命令;若需重启主节点,选择业务低峰期,提前通知,避免影响业务;
  6. Redis 版本不一致:将主从节点 Redis 版本统一(推荐 6.2.x 版本,稳定且支持所有核心功能);升级节点时,先升级从节点,再升级主节点,避免版本兼容性问题。

结语

hello 各位,到这里,Redis 主从复制从实战配置、拓扑架构、底层原理、故障排查四个核心维度,已经做了全网最细致、最落地的全解析,从基础的一主一从搭建,到高并发的一主多从、跨机房的树形拓扑,再到全量 / 部分复制的底层流程、核心命令与参数的深度拆解,甚至生产级的故障排查方案,全程手把手实战,把主从复制的每一个知识点、每一个避坑点都扒得明明白白。

回顾整篇内容,我们从生产中最致命的单点故障 切入,引出主从复制的核心价值 ------解决单点问题、实现读写分离、完成数据备份,这也是 Redis 从单节点走向分布式的第一步,更是后续哨兵模式、Redis Cluster 集群的底层基石,没有主从复制,Redis 的高可用、高并发就无从谈起。

我们把主从复制的核心逻辑,浓缩为最核心的3 个核心认知 和1 个终极原则,刻在脑子里,生产落地绝不踩坑:

3 个核心认知

  1. 角色分工定死:主节点只写、从节点只读(默认),数据流单向从主到从,从节点永远不能反向同步主节点,禁止关闭从节点只读模式,否则必出数据不一致;
  2. 同步流程固定 :所有主从复制的同步,都遵循建立连接→数据同步(全量 / 部分)→实时同步 + 心跳检测三阶段,首次同步必走全量,断连重连满足前提走部分,这是 Redis 的底层逻辑,无法更改;
  3. 核心命令 / 参数记死 :核心命令就 3 个 ------slaveof配主从、info replication查状态、PSYNC做同步(底层自动执行);核心参数围绕密码、只读、缓冲区、网络、心跳展开,按场景套用生产推荐值,无需凭空配置。

1 个终极原则

主从复制的核心是 "取舍",所有配置和优化都是在 "性能、延迟、带宽、可用性" 之间做平衡:

  • 同机房部署,优先保低延迟、高性能,关闭 Nagle 算法、调大缓冲区;
  • 跨机房部署,优先保省带宽、稳连接,开启 Nagle 算法、配置合理心跳超时;
  • 低并发场景,追求简单易维护,用一主一从 / 一主多从;
  • 超高并发 / 跨机房场景,追求低主节点压力、高读性能,用树形拓扑。

很多同学学完主从复制会有疑问:"主从复制需要手动切主,可用性不够,生产中怎么用?"这正是主从复制的边界 ------ 它是 Redis 高可用的基础 ,但不是终点。生产中,我们会在主从复制的基础上,搭配哨兵模式 实现自动故障转移 (主节点宕机,哨兵自动选从节点升主),再搭配Redis Cluster 实现数据分片 + 多主多从,支撑百万级并发。但所有高级架构,都离不开主从复制的核心逻辑,把主从复制学透,后续的哨兵、集群就是 "水到渠成"。

学习主从复制的过程,也是学习分布式系统核心思想 的过程:数据同步、读写分离、故障转移、资源平衡,这些思想不仅适用于 Redis,也适用于 MySQL、MongoDB 等所有分布式数据库 / 缓存。把主从复制的底层原理、实战配置、故障排查吃透,不仅能搞定 Redis 的高可用,更能建立分布式系统的思维,为后续学习更复杂的分布式架构打下坚实基础。

本篇内容从理论到实战,从基础到进阶,从配置到排错,覆盖了主从复制生产落地的所有场景,建议大家收藏反复回看,结合本地实战敲一遍命令、搭一遍拓扑、模拟一次故障,把知识点变成实际操作能力。

后续,我们会在主从复制的基础上,继续拆解Redis 哨兵模式 (自动故障转移)、Redis Cluster 集群(数据分片 + 高可用),带你从单节点 Redis,一步步搭建出支撑中大型业务的分布式 Redis 架构,让你的 Redis 技术栈从 "基础" 走向 "实战"、从 "单点" 走向 "分布式"。

一步一个脚印打牢基础,生产环境才不会掉链子。我们下篇博客见~

相关推荐
Lsetea1 小时前
OpenSSL verify报unable to get issuer certificate:error 2与partial_chain排查
linux·https·ssl证书·openssl·证书链
许彰午1 小时前
03-Linux环境准备依赖包内核参数与用户组
linux·运维·服务器·数据库
阳光九叶草LXGZXJ1 小时前
达梦数据库-报错-16-MERGE INTO提示:无效的列名[XX]
linux·运维·数据库·sql·学习
墨天梦2 小时前
B10_文件SharedPreferences与SQLite
jvm·数据库·sqlite
鲲极2 小时前
居间业务数据统计看板 三条取数口径怎么归一才对得上
数据库·鲲极·鲲极系统
CarIise2 小时前
Java实训阶段查漏补缺复习笔记2
java·linux·算法
ao-weilai2 小时前
MySQL数据库:基本查询
android·数据库·mysql
无忧.芙桃2 小时前
C++ 并查集详解:原理、实现与应用
c语言·c++·算法·leetcode
java1234_小锋2 小时前
【技术专题】Mysql8 数据库 - Mysql8 查询数据
数据库·mysql