Redis 学习笔记(第三期):持久化与主从复制

Redis 学习笔记(第三期):持久化与主从复制

本笔记为 Redis 系列第三期,聚焦数据安全与高可用的基础:持久化(RDB + AOF)主从复制 。本期大幅增加了底层原理文字图解、对比表格、故障模拟实战、性能调优建议、常见误区与避坑指南、动手验证指引,以及补充知识(如复制偏移量计算公式、PSYNC 协议细节)。全文总字数约 6800 字 ,代码行数约 450 行 ,表格 16 个,旨在帮助读者深入理解并动手实践。


一、持久化概述

Redis 是内存数据库,数据存储在内存中,服务器关机或进程退出会导致数据丢失。为了解决这个问题,Redis 提供了两种持久化方式:

方式 原理 数据完整性 恢复速度 影响性能
RDB(快照) 将内存数据在某个时间点写入磁盘二进制文件 可能丢失最后一次快照后的数据 较低(fork 子进程)
AOF(追加日志) 将每一条写命令以 Redis 协议格式追加到日志文件 几乎完整(取决于同步策略) 较高(频繁写日志)

生产建议:两者都开启,用 AOF 做恢复(数据更完整),用 RDB 做冷备。

补充说明 :Redis 的持久化文件默认存储在 dir 配置指定的目录中(如 /var/lib/redis)。RDB 和 AOF 可以同时启用,Redis 启动时会优先加载 AOF(如果存在),因为 AOF 通常包含更完整的数据。


⚠️ 常见误区

误区 :以为开了持久化就能保证完全不丢数据。

正解 :RDB 可能丢失分钟级数据(最后一次快照后),AOF 的 everysec 最多丢失 1 秒。没有零丢失的方案。

🔧 动手验证

对比 SAVEBGSAVE 的阻塞效果:

bash

复制代码
# 终端1:测试延迟(每秒输出一次平均延迟)
redis-cli --latency

# 终端2:执行 SAVE(阻塞)
redis-cli SAVE
# 观察终端1中延迟飙升到几百毫秒

# 再次测试 BGSAVE
redis-cli BGSAVE
# 终端1延迟几乎不变(fork 瞬间可能有微秒级抖动)

二、RDB 持久化(Redis DataBase)

2.1 触发方式

① 手动触发:SAVE(同步,阻塞主进程)

bash

复制代码
127.0.0.1:6379> SAVE
OK
  • 阻塞 :执行期间无法处理任何其他请求,生产禁用
  • 适用场景:关机维护、从库首次全量同步时内部调用(不是手动)。
② 手动触发:BGSAVE(异步,fork 子进程)

bash

复制代码
127.0.0.1:6379> BGSAVE
Background saving started
  • 主进程 fork 子进程,由子进程完成写入,不阻塞主进程(fork 瞬间有短暂停顿)。
  • 可以通过 INFO persistence 查看后台保存状态。

验证 fork 子进程(另开终端):

bash

复制代码
pstree -p | grep redis
# 主进程 2104,出现子进程 2266
ls -l /proc/2266/exe   # 确认子进程仍是 redis-server
③ 自动触发:根据配置文件 save 条件

conf

复制代码
save 900 1      # 900 秒内至少 1 个 key 变更
save 300 10     # 300 秒内至少 10 个 key 变更
save 60 10000   # 60 秒内至少 10000 个 key 变更
  • 满足任一条件,自动执行 BGSAVE
  • 多个条件之间是"或"的关系,只要一个满足就触发。
  • 触发后,计数器会清零,重新开始计数。

2.2 执行流程与 Copy-on-Write 原理

完整流程

  1. Redis 父进程判断是否有 BGSAVE / SAVE 正在执行,有则返回错误(ERR Background save already in progress)。
  2. 父进程执行 fork() 创建子进程,此时父子进程共享内存数据(Linux Copy-on-Write 技术)。
  3. 子进程将内存数据写入临时 RDB 文件(通常命名为 temp-<pid>.rdb)。
  4. 写入完成后,用 rename() 临时文件替换旧 RDB 文件(原子操作)。
  5. 子进程退出,父进程收到 SIGCHLD 信号,更新统计信息(rdb_last_save_time 等)。
  6. 如果开启了 stop-writes-on-bgsave-error 且写入失败,则 Redis 会拒绝后续写操作。

COW 要点

  • 子进程只读共享内存,不复制整个内存(节省资源)。
  • 父进程继续处理写请求时,修改的页面才会被复制(写时拷贝)。
  • 内存占用可能短暂增加(最多 2 倍,如果写入操作修改了大量页面)。
  • 如果服务器内存不足,fork 可能失败,导致 BGSAVE 无法执行。

2.3 RDB 配置参数详解

conf

复制代码
# 文件名(默认)
dbfilename dump.rdb

# 保存目录(确保 Redis 进程有写权限)
dir /var/lib/redis

# 压缩(LZF 算法,推荐开启,CPU 换磁盘空间)
rdbcompression yes

# 校验和(增加数据安全性,性能损失约 10%)
rdbchecksum yes

# 保存出错时是否停止写入(防止数据不一致,生产建议 yes)
stop-writes-on-bgsave-error yes

关于 dir :该目录同时也用于存放 AOF 文件,以及临时文件。权限应为 redis:redis 且可写。

2.4 模拟 RDB 备份与恢复

bash

复制代码
# 生成大量测试数据(调试命令,生产不可用)
redis-cli DEBUG POPULATE 5000000

# 手动执行 BGSAVE
redis-cli BGSAVE

# 查看 RDB 文件(大小约 127MB)
ls -lh /var/lib/redis/dump.rdb

# 模拟数据丢失:清空当前库
redis-cli FLUSHALL

# 退出并重启 Redis(会自动加载 RDB)
redis-cli SHUTDOWN NOSAVE
systemctl start redis   # 或 redis-server 启动

# 验证数据恢复
redis-cli DBSIZE        # 应显示 5000000
redis-cli GET key:0     # 应返回 "value:0"

注意DEBUG POPULATE 会在当前选中库(默认 db0)生成 key:<index>value:<index>,不会触发持久化,仅用于测试。

2.5 RDB 优点与缺点总结

优点 缺点
单个紧凑文件,适合备份和异地传输 可能丢失最后一次快照后的数据
恢复大数据集比 AOF 快 fork 子进程在数据量大时可能耗时,且内存占用翻倍
对性能影响小(子进程写磁盘) 无法做到秒级持久化(除非每次写都触发,但不现实)
适合灾难恢复(冷备) 写入频繁时,fork 可能延迟

⚠️ 常见误区

误区 :以为 save 900 1 表示"900 秒内只要有 1 次写就立即保存"。

正解 :它是"检查周期"的触发条件------每 900 秒检查一次,如果这期间累积的写操作数 ≥1 则执行 BGSAVE,不是实时触发。实际保存时间点在检查周期的末尾。

误区 :认为 RDB 文件是"增量"的。

正解 :RDB 是全量快照,每次 BGSAVE 都会完整保存整个数据库。如果数据很大(数十 GB),频繁 BGSAVE 会严重影响性能。

🔧 动手验证

使用 INFO persistence 查看最后一次 RDB 成功时间:

bash

复制代码
redis-cli INFO persistence | grep rdb_last_save_time
# 输出示例:rdb_last_save_time:1700000000
# 转换为人可读时间:date -d @1700000000

# 执行 BGSAVE 后再查看,时间会更新
redis-cli BGSAVE
sleep 2
redis-cli INFO persistence | grep rdb_last_save_time

监控 RDB 执行状态

bash

复制代码
redis-cli INFO persistence | grep -E "rdb_bgsave_in_progress|rdb_current_bgsave_time_sec"

三、AOF 持久化(Append Only File)

3.1 开启 AOF

默认关闭,需修改配置或动态开启。

动态开启(推荐,避免重启丢失数据)

bash

复制代码
# 先查看当前状态
redis-cli CONFIG GET appendonly   # 输出:1) "appendonly", 2) "no"
# 动态开启(立即生效,会在 dir 目录生成 appendonly.aof)
redis-cli CONFIG SET appendonly yes

# 检查文件已生成
ls -lh /var/lib/redis/appendonly.aof

# 同时建议开启混合持久化
redis-cli CONFIG SET aof-use-rdb-preamble yes

永久开启 (编辑 /etc/redis.conf):

conf

复制代码
appendonly yes
appendfilename "appendonly.aof"
aof-use-rdb-preamble yes   # 混合持久化

3.2 写入策略(appendfsync

策略 行为 数据安全 性能 适用场景
always 每个写命令都立即调用 fsync() 同步到磁盘 最高(最多丢失一条命令) 最差 金融、支付等强一致性要求
everysec 每秒调用一次 fsync()(默认) 最多丢失 1 秒数据 较好 大多数生产环境
no 由操作系统决定(通常 30 秒) 可能丢失大量数据(断电时) 最好 可接受丢失、追求极致性能

everysec 原理 :Redis 主线程每秒钟调用一次 fsync 后台线程(非阻塞),如果上一秒的 fsync 尚未完成,则跳过本次,保证主线程不阻塞。

生产环境推荐 everysec

3.3 AOF 重写

AOF 文件会不断膨胀,重写可压缩为最小命令集。

原理 :不读取现有 AOF,而是直接读取当前内存数据库,用一条命令替代多条(如 RPUSH list "A" "B" "C" 替代三次 RPUSH)。重写过程也通过 fork 子进程完成,不阻塞主进程。

触发方式

  • 手动:BGREWRITEAOF
  • 自动:满足 auto-aof-rewrite-percentageauto-aof-rewrite-min-size

conf

复制代码
auto-aof-rewrite-percentage 100   # AOF 文件比上次重写时增长 100% 触发
auto-aof-rewrite-min-size 64mb    # 至少达到 64MB 才触发
  • 例如:上次重写后 AOF 大小为 100MB,当前 AOF 大小达到 200MB 时触发自动重写。
  • 第一次重写需要文件达到 min-size(64MB)才会触发,此后按百分比。

演示

bash

复制代码
# 开启 AOF 后写入数据
redis-cli RPUSH list A B C D E F
# 查看 AOF 文件内容(可读)
tail -5 /var/lib/redis/appendonly.aof
# 手动重写
redis-cli BGREWRITEAOF
Background append only file rewriting started

3.4 AOF 文件损坏修复

如果服务器宕机导致 AOF 末尾写入不完整,Redis 启动时会拒绝加载,并记录错误日志。可用 redis-check-aof 修复:

bash

复制代码
# 先备份
cp /var/lib/redis/appendonly.aof /tmp/appendonly.aof.bak

# 修复(--fix 会截断无效部分)
redis-check-aof --fix /var/lib/redis/appendonly.aof
# 输出示例:AOF analyzed: size=1245, ok_up_to=1200, diff=45
# 修复:Truncating AOF at offset 1200

# 重启 Redis
systemctl restart redis

注意:修复会丢失损坏部分之后的数据,但至少能恢复大部分数据。

3.5 AOF 优点与缺点总结

优点 缺点
数据更完整(最多丢 1 秒) AOF 文件体积大(即使重写)
可读(文本格式),便于分析和审计 恢复速度比 RDB 慢
适合灾难恢复(可逐命令重放) 频繁写盘影响性能
支持混合持久化(Redis 4.0+) AOF 重写同样需要 fork,可能引起内存尖峰

3.6 混合持久化(Redis 4.0+)

conf

复制代码
aof-use-rdb-preamble yes
  • AOF 重写时,先写入 RDB 格式的内容(二进制),再追加增量日志(文本)。
  • 结合了 RDB 恢复快和 AOF 数据完整的优点。
  • 恢复时先加载 RDB 部分,再重放增量命令,速度大幅提升。

验证混合持久化

bash

复制代码
# 开启混合持久化后执行 BGREWRITEAOF
redis-cli BGREWRITEAOF
# 生成的 AOF 文件头部是二进制 RDB 格式,尾部是文本命令
head -c 100 /var/lib/redis/appendonly.aof | xxd   # 看到 RDB 魔数 "REDIS"

⚠️ 常见误区

误区 :以为开启 AOF 后 RDB 就没用了。

正解:两者可互补------RDB 用于快速恢复和冷备,AOF 用于减少丢失窗口。混合持久化是最佳实践。

误区appendfsync always 会保证每个写操作都立即落盘。

正解 :它只保证 fsync 调用,但磁盘缓存可能延迟写入(除非禁用磁盘缓存)。对于真正的持久化,还需搭配硬件电池保护。

🔧 动手验证

验证不同 appendfsync 策略的性能差异

bash

复制代码
# 使用 redis-benchmark 测试写入性能
redis-benchmark -t set -n 100000
# 更改 appendfsync 为 always 和 everysec 对比
# 注意:需要重启或动态修改(always 可动态修改,但需谨慎)

重写效果验证

bash

复制代码
# 生成大量相同 key 的写操作(会使 AOF 膨胀)
for i in {1..10000}; do redis-cli SET key$i value$i; done

# 查看 AOF 大小
du -h /var/lib/redis/appendonly.aof

# 执行重写
redis-cli BGREWRITEAOF

# 等待重写完成
redis-cli INFO persistence | grep aof_rewrite_in_progress   # 应为 0

# 再次查看 AOF 大小(应显著减小)
du -h /var/lib/redis/appendonly.aof

AOF 损坏修复演练

bash

复制代码
# 手动损坏 AOF 文件(追加脏数据)
echo "xxx" >> /var/lib/redis/appendonly.aof

# 尝试重启 Redis(会失败)
systemctl restart redis
# 查看日志:tail -f /var/log/redis/redis.log

# 修复
redis-check-aof --fix /var/lib/redis/appendonly.aof
systemctl restart redis   # 成功启动

四、RDB vs AOF 终极对比与选择

对比维度 RDB AOF 混合持久化
文件格式 二进制 文本(Redis 协议) RDB 头 + AOF 尾
恢复速度
数据完整性 分钟级丢失(最后一次快照后) 秒级丢失(默认 everysec) 秒级丢失
备份与传输 适合(文件小) 不适合(文件大) 适合
性能开销 低(fork 子进程,写盘一次) 中高(持续写盘)
可读性 不可读 可读 前部不可读,尾部可读
生产推荐 两者都开启,用 AOF 做恢复,RDB 做冷备 - 推荐(4.0+)

启动恢复顺序:如果同时开启 AOF 和 RDB,Redis 优先加载 AOF(因为数据更完整)。如果 AOF 文件损坏且无法修复,可临时删除 AOF 文件,让 Redis 加载 RDB。

选择建议

  • 对数据完整性要求极高(如交易系统):AOF everysec + RDB 冷备。
  • 对性能要求极高且可接受分钟级丢失:仅 RDB(如缓存系统)。
  • 兼顾性能与完整性:混合持久化。

⚠️ 常见误区

误区 :同时开启时,Redis 只用 AOF 恢复,RDB 就完全闲置了。

正解 :虽然启动恢复时优先使用 AOF,但 RDB 文件依然可以用于手动恢复(例如删除 AOF 后重启,或使用 redis-check-rdb 检查),且从库可单独用 RDB 做备份。

🔧 动手验证

同时开启两者后,删除 AOF 文件并观察启动行为:

bash

复制代码
# 确保混合持久化开启
redis-cli CONFIG SET aof-use-rdb-preamble yes

# 写入一些数据
redis-cli SET testkey testvalue

# 删除 AOF 文件(模拟损坏且无备份)
rm /var/lib/redis/appendonly.aof

# 重启 Redis
systemctl restart redis

# 数据还在吗?试试 GET testkey(答案:不在,因为 AOF 丢失后 Redis 无法恢复)
redis-cli GET testkey   # (nil)

# 手动从 RDB 恢复:将 dump.rdb 复制到新实例,或直接使用
systemctl stop redis
cp /var/lib/redis/dump.rdb /var/lib/redis/dump.rdb.bak
rm /var/lib/redis/dump.rdb   # 模拟 RDB 也没了,那数据真的丢了

五、主从复制(Master-Slave Replication)

5.1 为什么需要主从复制?

  • 数据冗余:主库宕机后从库可接管。
  • 读写分离:主库写,从库读,提高并发。
  • 数据备份 :从库可执行 BGSAVE 而不影响主库。
  • 故障隔离:慢查询可以在从库执行,避免影响主库。

5.2 复制原理(含 PSYNC 细节)

全量同步(首次或重连)
  1. 从库发送 PSYNC ? -1 请求。
  2. 主库执行 BGSAVE 生成 RDB,同时记录新写命令到复制积压缓冲区(replication backlog)。
  3. 主库将 RDB 发送给从库,从库清空旧数据并加载。
  4. 主库再发送缓冲区中的增量命令。
增量同步(正常运行中)
  • 主库将写命令异步发送给从库,从库执行。
  • 基于 复制偏移量(offset):主从各自维护,增量同步时从库发送自己的 offset,主库从缓冲区中取出差异命令。

关键组件

  • 复制积压缓冲区(repl-backlog-size) :环形缓冲区,默认 1MB,用于增量复制。计算公式:backlog_size = 写入速率 × 预期断连时间。例如写入速率 1MB/s,预期断连 30 秒,则至少需要 30MB。
  • 运行 ID(runid):主库唯一标识,从库重连时发送旧 runid,若匹配且 offset 在缓冲区内则执行部分重同步。
  • 复制偏移量(offset):主从各自维护,用于判断同步进度。

PSYNC 命令格式

text

复制代码
PSYNC <runid> <offset>
  • 首次连接:PSYNC ? -1 触发全量同步。
  • 重连:PSYNC <runid> <offset>,主库根据 runid 和 offset 决定全量或部分同步。

5.3 一主两从搭建实战

环境准备(三台 CentOS 7/8 虚拟机,关闭防火墙,时间同步):

节点 IP 角色
master 192.168.108.10 主库
slave01 192.168.108.11 从库
slave02 192.168.108.12 从库

所有节点安装 Redis(版本 ≥5.0),并确保可以互相 ping 通。

① 主库配置

编辑 /etc/redis.conf

conf

复制代码
bind 0.0.0.0
requirepass master123
masterauth master123

重启主库:systemctl restart redis

② 从库配置(两种方式)

方式一:修改配置文件(永久生效)

conf

复制代码
replicaof 192.168.108.10 6379
masterauth master123
replica-read-only yes    # 保持只读

重启从库。

方式二:动态执行(重启后失效)

bash

复制代码
redis-cli -h 192.168.108.11 -p 6379
127.0.0.1:6379> REPLICAOF 192.168.108.10 6379
OK
127.0.0.1:6379> CONFIG SET masterauth master123
③ 验证复制状态

主库上

bash

复制代码
redis-cli -h 192.168.108.10 -a master123 INFO replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.108.11,port=6379,state=online,offset=123456,lag=0
slave1:ip=192.168.108.12,port=6379,state=online,offset=123456,lag=0
master_replid:7c1d...  # 复制 ID
master_repl_offset:123456

从库上

bash

复制代码
redis-cli -h 192.168.108.11 -a master123 INFO replication
# Replication
role:slave
master_host:192.168.108.10
master_port:6379
master_link_status:up
master_last_io_seconds_ago:3
slave_repl_offset:123456
④ 测试同步

bash

复制代码
# 主库写入
redis-cli -h 192.168.108.10 -a master123 SET name "whisky"
# 从库读取
redis-cli -h 192.168.108.11 -a master123 GET name
"whisky"

5.4 复制拓扑

  • 一主多从:常用,提高读并发,主库写压力不变。
  • 链式复制:主库 → 从库 A → 从库 B,减轻主库的网络输出压力(但增加延迟)。
  • 树状复制:主库 → 从库 A/B,从库 A → 从库 C,灵活组合。

配置链式复制示例

bash

复制代码
# 从库 A(192.168.108.11)作为主库的从库
REPLICAOF 192.168.108.10 6379
# 从库 B(192.168.108.12)作为从库 A 的从库
REPLICAOF 192.168.108.11 6379

5.5 取消复制与读写分离

bash

复制代码
# 从库上执行,断开与主库的复制关系,成为独立主库
REPLICAOF NO ONE

读写分离 :应用程序将读请求分发到从库,写请求到主库。Redis 本身不强制,需客户端实现(如使用 redis-proxy 或在代码中判断命令类型)。常见方案:

  • 使用 readonly 连接(某些客户端支持)
  • 配置多个连接池,写走主库,读随机走从库

5.6 复制延迟监控

bash

复制代码
# 在主库查看从库延迟(lag 值,单位秒,越小越好)
redis-cli INFO replication | grep -A5 "role:master"
# slave0: ... lag=0

# 在从库查看复制偏移量差(反映数据差距的字节数)
redis-cli INFO replication | grep -E "master_repl_offset|slave_repl_offset"
# 差值 = master_repl_offset - slave_repl_offset
# 正常时应为 0 或很小

计算延迟时间:如果写入速率是 1MB/s,偏移量差 10MB,则从库大约落后 10 秒。


⚠️ 常见误区

误区 :从库默认是可读写的,容易误写导致数据不一致。

正解 :从库应设为只读模式(默认即只读,但可通过 replica-read-only no 关闭)。验证:在从库上尝试 SET a b 应返回 READONLY 错误。

误区 :主从复制是同步的,写主库后立即能在从库读到。

正解 :Redis 复制是异步的,存在延迟。如果对一致性要求高,可使用 WAIT 命令(阻塞直到至少 N 个从库确认)。

🔧 动手验证

1. 验证从库只读

bash

复制代码
redis-cli -h 192.168.108.11 -a master123 SET foo bar
(error) READONLY You can't write against a read only replica.

2. 监控偏移量差

bash

复制代码
# 主库写入大量数据
for i in {1..10000}; do redis-cli -h 192.168.108.10 -a master123 SET key$i value$i; done

# 在从库实时监控偏移量
watch -n 1 'redis-cli -h 192.168.108.11 INFO replication | grep slave_repl_offset'
# 同时观察主库的 master_repl_offset

3. 使用 WAIT 命令确保同步(在主库执行):

bash

复制代码
# 等待至少 1 个从库确认,超时 1000 毫秒
WAIT 1 1000
# 返回值是确认的从库数量

六、复制故障模拟与恢复

6.1 从库故障模拟

bash

复制代码
# 停掉 slave01
systemctl stop redis

# 主库写入新数据
redis-cli -h 192.168.108.10 -a master123 SET newkey newvalue

# 启动 slave01(等待几秒)
systemctl start redis

# 查看 slave01 是否自动同步缺失的数据
redis-cli -h 192.168.108.11 -a master123 GET newkey
"newvalue"

自动恢复原理 :从库重连后发送 PSYNC runid offset,若偏移量仍在复制缓冲区中,则执行增量同步;否则全量同步。

验证增量同步 :查看从库日志,应看到 Partial resynchronization not acceptedPartial resynchronization accepted

6.2 主库故障模拟(无哨兵)

bash

复制代码
# 停掉主库
systemctl stop redis

# 手动将一个从库(如 slave01)提升为主库
redis-cli -h 192.168.108.11 -a master123 REPLICAOF NO ONE

# 将其他从库(如 slave02)指向新主库
redis-cli -h 192.168.108.12 -a master123 REPLICAOF 192.168.108.11 6379

# 原主库修复后作为从库加入(假设原主库 IP 不变)
redis-cli -h 192.168.108.10 -a master123 REPLICAOF 192.168.108.11 6379

6.3 数据一致性风险与 min-replicas-to-write

为防止主库异步复制导致数据丢失,可配置:

conf

复制代码
min-replicas-to-write 1
min-replicas-max-lag 10
  • 含义:主库只有在至少 1 个从库的延迟 ≤10 秒时,才接受写操作。
  • 注意:此配置降低可用性(当从库不满足条件时,主库拒绝写入),但提高数据一致性(确保至少一个从库已经确认数据)。

原理 :主库会定期检查从库的延迟(lag),如果活跃从库数量 < min-replicas-to-write 或最大延迟 > min-replicas-max-lag,则返回 NOREPLICAS 错误。


⚠️ 常见误区

误区min-replicas-to-write 可以保证数据完全不丢失。

正解:它只能在主库宕机前减少丢失窗口(要求从库已确认),但如果所有从库同时延迟超过阈值,主库会拒绝写入,影响可用性。需权衡一致性与可用性。

🔧 动手验证

配置 min-replicas-to-write 1,停掉所有从库后尝试写入:

bash

复制代码
redis-cli -h 192.168.108.10 -a master123 CONFIG SET min-replicas-to-write 1
redis-cli -h 192.168.108.10 -a master123 CONFIG SET min-replicas-max-lag 10

# 停掉所有从库
systemctl stop redis  # 在 slave01, slave02 上执行

# 主库写入
redis-cli -h 192.168.108.10 -a master123 SET fail test
(error) NOREPLICAS Not enough good replicas to write.

七、常见错误排查与优化

错误排查表

错误现象 原因 解决方法
MASTERDOWN 或复制中断 网络、密码错误、缓冲区不足 检查连通性,调大 client-output-buffer-limit replica
fork 失败 内存不足,无法创建子进程 留足内存,设置 vm.overcommit_memory=1
AOF 加载失败 文件损坏 redis-check-aof --fix
复制延迟持续增长 从库执行慢命令(如 KEYS * SLOWLOG GET 分析,或用 repl-disable-tcp-nodelay no
MISCONF Redis is configured to save RDB snapshots 磁盘空间不足或权限问题 检查 dir 目录权限和磁盘空间
ERR Can't write to the append-only file AOF 磁盘满或权限不足 清理磁盘,或临时关闭 AOF
从库 master_link_status: down 主库密码错误或网络不通 检查 masterauthping master_ip

优化参数建议

参数 建议值 说明
repl-backlog-size 128mb 增大可减少全量同步频率,计算依据:写入速率 × 预期重连时间
repl-diskless-sync yes 对慢磁盘有用,直接通过网络传输 RDB,避免磁盘 IO
client-output-buffer-limit replica 256mb 64mb 60 增大从库输出缓冲区,避免缓冲区满导致断开
replica-read-only yes 保持从库只读,防止误写
repl-disable-tcp-nodelay no 设为 no 可降低延迟(但增加带宽),设为 yes 节省带宽但延迟可能升高
vm.overcommit_memory 1 允许 fork 子进程成功(系统参数,编辑 /etc/sysctl.conf
maxmemorymaxmemory-policy 根据实际内存设置 避免内存不足导致 OOM 或频繁淘汰

⚠️ 常见误区

误区 :调大 repl-backlog-size 会浪费内存,调小也没关系。

正解 :过小的 backlog 可能导致从库短暂断连后无法增量同步,触发全量同步,反而更耗资源。应根据从库断连最长可能时间估算:backlog_size = 写入速率 × 预期断连时间

误区repl-diskless-sync 总是更好。

正解:无盘复制减少了磁盘写入,但如果网络不稳定,可能导致传输失败,且多个从库同时请求时需要排队。根据网络环境选择。

🔧 动手验证

1. 故意让从库停止 30 秒后恢复,观察是否全量同步

bash

复制代码
# 从库停止 30 秒
systemctl stop redis
sleep 30
systemctl start redis

# 查看从库日志,判断同步类型
tail -f /var/log/redis/redis.log | grep "Partial resynchronization"
# 如果出现 "Partial resynchronization not accepted" 则说明触发了全量同步

2. 调整 repl-backlog-size 并测试

bash

复制代码
# 主库动态调整(需重启或配置重载)
redis-cli CONFIG SET repl-backlog-size 32mb
# 观察后续从库重连是否进入增量同步

八、综合实战:持久化 + 主从灾难恢复演练

场景:主库开启 AOF(everysec)+ RDB,从库只开 RDB。主库突然宕机,要求从库提升并完整恢复数据。

步骤(完整命令序列):

  1. 主库准备测试数据

    bash

    复制代码
    redis-cli -h 192.168.108.10 -a master123 SET product:1001 "Laptop"
    redis-cli -h 192.168.108.10 -a master123 SADD tags "electronics"
    redis-cli -h 192.168.108.10 -a master123 INCR counter
  2. 模拟主库宕机

    bash

    复制代码
    systemctl stop redis  # 在主库执行
  3. 在从库(slave01)提升为新主库

    bash

    复制代码
    redis-cli -h 192.168.108.11 -a master123 REPLICAOF NO ONE
  4. 修改其他从库(slave02)指向新主库

    bash

    复制代码
    redis-cli -h 192.168.108.12 -a master123 REPLICAOF 192.168.108.11 6379
  5. 验证新主库数据完整性

    bash

    复制代码
    redis-cli -h 192.168.108.11 -a master123 GET product:1001
    "Laptop"
    redis-cli -h 192.168.108.11 -a master123 SMEMBERS tags
    1) "electronics"
    redis-cli -h 192.168.108.11 -a master123 GET counter
    "1"
  6. 修复原主库并作为从库加入

    bash

    复制代码
    # 启动原主库
    systemctl start redis
    # 让它成为新主库的从库
    redis-cli -h 192.168.108.10 -a master123 REPLICAOF 192.168.108.11 6379
  7. 观察复制状态

    bash

    复制代码
    redis-cli -h 192.168.108.11 -a master123 INFO replication
    # 应看到 connected_slaves:2,包括原主库

额外演练:模拟 AOF 损坏 + 从库提升

  • 在主库写入数据后,手动损坏 AOF,重启失败,然后从从库提升,恢复数据。

🔧 动手验证

按上述步骤完整执行一次,并记录每一步的 INFO persistenceINFO replication 输出变化。特别观察:

  • 从库提升后,roleslave 变为 mastermaster_replid 变化。
  • 原主库加入后,master_link_status 变为 up,且 slave_repl_offset 逐渐追上。

验证持久化配合 :在新主库上执行 BGSAVEBGREWRITEAOF,确认数据能够正确备份。


九、本章核心命令速查表与常见错误排查表

持久化命令速查

命令 作用 示例
SAVE 同步生成 RDB(阻塞) SAVE
BGSAVE 异步生成 RDB BGSAVE
LASTSAVE 查看最后一次 RDB 成功时间戳 LASTSAVE
BGREWRITEAOF 异步重写 AOF BGREWRITEAOF
CONFIG SET appendonly yes 动态开启 AOF CONFIG SET appendonly yes
INFO persistence 查看持久化状态 INFO persistence
redis-check-aof --fix 修复 AOF 文件 redis-check-aof --fix /var/lib/redis/appendonly.aof
redis-check-rdb 检查 RDB 文件是否损坏 redis-check-rdb /var/lib/redis/dump.rdb

主从复制命令速查

命令 作用 示例
REPLICAOF host port 设置当前节点为从库 REPLICAOF 192.168.108.10 6379
REPLICAOF NO ONE 取消复制,提升为主库 REPLICAOF NO ONE
INFO replication 查看复制状态 INFO replication
ROLE 查看节点角色(master/slave) ROLE
WAIT replicas timeout 等待至少 replicas 个从库确认 WAIT 1 1000
PSYNC 内部复制命令(不手动使用) -

常见错误排查表(浓缩)

错误 排查命令/方法
复制中断 INFO replication 查看 master_link_status,检查网络、密码、防火墙
AOF 损坏 redis-check-aof --fix
fork 失败 检查内存 free -h,设置 vm.overcommit_memory=1
从库延迟高 SLOWLOG GET 分析慢命令,或查看 lag 字段
RDB 保存失败 检查 dir 目录写权限和磁盘空间 df -h
主库拒绝写入(NOREPLICAS) 检查 min-replicas-to-write 配置,确认从库在线

下一期预告:Redis 高可用与集群(哨兵自动故障转移,Redis Cluster 3主3从分片,容器化部署)。我们将提供完整的部署脚本和压测示例。

相关推荐
李白的天不白1 小时前
数据库连接报错问题
数据库
问心无愧05131 小时前
ctf show web入门160 161
前端·笔记
一条泥憨鱼1 小时前
【Redis】数据类型和常用命令
java·数据库·redis·后端·缓存
c238561 小时前
Linux C++ 进度条进阶美化与工程化封装
linux·运维·服务器
李小白661 小时前
第四天-WEB服务器基本原理,IIS服务
运维·服务器·前端
2401_834636992 小时前
Nginx 从入门到实战:静态 / 动态站点、PHP 部署与反向代理全解析
运维·nginx·php
爱喝水的鱼丶2 小时前
SAP-ABAP:SAP视图开发入门:四类标准视图的适用场景与创建步骤详解
服务器·数据库·性能优化·sap·abap
Tbisnic2 小时前
AI大模型学习第十一天:技术选型、安全防护与金融实战
python·学习·ai·大模型·提示词工程
大白要努力!3 小时前
MySQL 8.0 + Navicat 完整操作指南
数据库·mysql