当前位置: 首页 > news >正文

【redis】主从复制

Redis的单机模式仅部署单个实例,一旦节点宕机或网络故障,所有依赖Redis的服务将不可用,这就是所谓的单点故障问题。单节点需承担全部读写请求,并发量高时可能成为性能瓶颈。单节点受限于物理内存容量,无法突破内存物理上限存储海量数据。所有请求都怼到一个实例,磁盘IO、网络IO、带宽、CPU等资源都会成为瓶颈。

主从复制(Master-Replica)通过部署主节点(Master)和多个从节点(Replica),实现数据副本分发:

  • 主节点:处理所有写请求,数据变更后异步/半同步复制到从节点。
  • 从节点:以只读形式提供数据查询,承担读请求压力。

注意:读写分离并不是Redis自带,需要客户端手动实现。

主从复制的多种拓扑结构

Redis主从复制支持多种拓扑结构,不同结构适用于不同场景,核心目的是实现数据冗余读写分离高可用

一主一从(Master + Single Replica)

单个主节点(Master)搭配一个从节点(Replica),从节点通过 replicaof 命令与主节点建立复制关系。

工作原理

  • 主节点处理所有写请求,从节点异步复制主节点数据。
  • 从节点可接受只读请求,分担主节点的读压力。

优点

  • 简单易用:配置简单,适合快速搭建备份环境。
  • 基础高可用:主节点故障时,可手动将从节点提升为主节点。
  • 数据冗余:至少保留一份完整数据副本。

缺点

  • 读扩展有限:仅一个从节点,读性能提升有限。
  • 资源利用率低:从节点可能长期处于低负载状态。

适用场景

  • 小型系统的基础数据备份。
  • 测试环境验证主从复制功能。
  • 对读性能要求不高的容灾场景。

一主多从(Master + Multiple Replicas)

一个主节点(Master)连接多个从节点(Replicas),所有从节点直接复制主节点数据。

工作原理

  • 主节点处理写请求,所有从节点异步复制主节点数据。
  • 读请求可分摊到多个从节点,实现水平扩展

优点

  • 高读吞吐量:多个从节点并行处理读请求,适合读多写少场景。
  • 灵活扩展:按需动态增加从节点,提升读性能。
  • 多副本冗余:数据安全性更高,多个从节点可同时故障。

缺点

  • 主节点压力大:所有从节点直接连接主节点,主节点需处理大量复制流量。
  • 网络带宽消耗:主节点需向多个从节点发送相同数据,可能成为网络瓶颈。

适用场景

  • 高并发读场景(如热点数据查询、排行榜读取)。
  • 多机房部署时,从节点分布在多个机房实现就近读取。
  • 需要多副本冗余的高可靠性系统。

级联复制(Chained Replication)

主节点 → 从节点(中间层) → 更多从节点,形成树状层级结构。例如:主节点A复制到从节点B,从节点B再作为“主节点”复制到从节点D、E。

工作原理

  • 中间层从节点既是主节点的副本,又是下级节点的“主节点”。
  • 数据从主节点逐级异步复制到下级节点。

优点

  • 降低主节点压力:主节点只需复制到少数中间层节点,减少直接连接的从节点数量。
  • 优化网络带宽:分散复制流量,避免主节点成为带宽瓶颈。
  • 跨地域复制:中间层节点可部署在不同地域,减少跨区域带宽占用。

缺点

  • 数据延迟累积:层级越深,底层节点数据同步延迟可能越大。
  • 故障风险扩散:中间层节点故障会影响其下级所有从节点。
  • 运维复杂度高:需监控多层级节点,故障排查难度增加。

适用场景

  • 主节点带宽有限时,需支撑大量从节点。
  • 多数据中心部署(如主节点在中心机房,中间层节点分布到边缘节点)。
  • 需要层级化管理的企业级架构(如总部-分公司的数据同步)。

对比与选型建议

类型读扩展能力主节点压力数据延迟适用规模典型场景
一主一从小型系统数据备份、基础容灾
一主多从中型系统高并发读、多副本冗余
树状结构高(累积)大型分布式系统跨地域复制、带宽优化

级联主从复制实战部署

Redis节点规划:

  • Master: 127.0.0.1:6380
  • Slave1: 127.0.0.1:6381(直连Master)
  • Slave2: 127.0.0.1:6382(直连Slave1)

在/test/目录分别新建/test/6380、/test/6381、/test/6382三个目录,用来存放redis的数据文件。

启动Master,这里为了便于演示,查看日志情况,都使用非守护进程的方式启动:

$ redis-server --dir /test/6380 --port 6380

启动两个Slave:

$ redis-server --dir /test/6381 --port 6381
$ redis-server --dir /test/6382 --port 6382

现在三台Redis还没有建立任何关系,现在使用REPLICAOF命令对Slave1进行主从复制(旧版本使用slaveof命令):

$ redis-cli -p 6381 REPLICAOF 127.0.0.1 6380
OK

在Master节点的日志可以看到与slave1建立复制关系:

4568:M 16 Apr 2025 14:13:32.876 * Replica 127.0.0.1:6381 asks for synchronization
4568:M 16 Apr 2025 14:13:32.876 * Partial resynchronization not accepted: Replication ID mismatch (Replica asked for '5d5d90144633f080a3d7d3716c9f8e4368a8d934', my replication IDs are 'a532518e375fa630202ed97a4cfb6793994e84f6' and '0000000000000000000000000000000000000000')
4568:M 16 Apr 2025 14:13:32.876 * Replication backlog created, my new replication IDs are '8b9acbd5b3737e524d64c2dfb6ac4c9022439b8e' and '0000000000000000000000000000000000000000'
4568:M 16 Apr 2025 14:13:32.876 * Starting BGSAVE for SYNC with target: disk
4568:M 16 Apr 2025 14:13:32.876 * Background saving started by pid 4584
4584:C 16 Apr 2025 14:13:32.878 * DB saved on disk
4584:C 16 Apr 2025 14:13:32.879 * RDB: 0 MB of memory used by copy-on-write
4568:M 16 Apr 2025 14:13:32.954 * Background saving terminated with success
4568:M 16 Apr 2025 14:13:32.954 * Synchronization with replica 127.0.0.1:6381 succeeded

同样在Slave1节点的日志可以看到:

4573:S 16 Apr 2025 14:13:32.875 * MASTER <-> REPLICA sync started
4573:S 16 Apr 2025 14:13:32.875 * REPLICAOF 127.0.0.1:6380 enabled (user request from 'id=3 addr=127.0.0.1:35164 laddr=127.0.0.1:6381 fd=8 name= age=0 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=44 qbuf-free=40910 argv-mem=22 obl=0 oll=0 omem=0 tot-mem=61486 events=r cmd=replicaof user=default redir=-1')
4573:S 16 Apr 2025 14:13:32.875 * Non blocking connect for SYNC fired the event.
4573:S 16 Apr 2025 14:13:32.875 * Master replied to PING, replication can continue...
4573:S 16 Apr 2025 14:13:32.875 * Trying a partial resynchronization (request 5d5d90144633f080a3d7d3716c9f8e4368a8d934:1).
4573:S 16 Apr 2025 14:13:32.876 * Full resync from master: 8b9acbd5b3737e524d64c2dfb6ac4c9022439b8e:0
4573:S 16 Apr 2025 14:13:32.876 * Discarding previously cached master state.
4573:S 16 Apr 2025 14:13:32.954 * MASTER <-> REPLICA sync: receiving 175 bytes from master to disk
4573:S 16 Apr 2025 14:13:32.954 * MASTER <-> REPLICA sync: Flushing old data
4573:S 16 Apr 2025 14:13:32.954 * MASTER <-> REPLICA sync: Loading DB in memory
4573:S 16 Apr 2025 14:13:32.956 * Loading RDB produced by version 6.2.6
4573:S 16 Apr 2025 14:13:32.956 * RDB age 0 seconds
4573:S 16 Apr 2025 14:13:32.956 * RDB memory usage when created 1.83 Mb
4573:S 16 Apr 2025 14:13:32.956 # Done loading RDB, keys loaded: 0, keys expired: 0.
4573:S 16 Apr 2025 14:13:32.956 * MASTER <-> REPLICA sync: Finished with success

对Slave2执行同样的操作,同样可以在Slave1和Slave2中日志中观察到建立复制关系。

在主节点(Master)上查看复制状态:

$ redis-cli -p 6380 info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6381,state=online,offset=1676,lag=1
master_failover_state:no-failover
master_replid:8b9acbd5b3737e524d64c2dfb6ac4c9022439b8e
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1676
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:1676

在第一级从节点(Slave1)上查看复制状态:

$ redis-cli -p 6381 info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6380
master_link_status:up
master_last_io_seconds_ago:10
master_sync_in_progress:0
slave_read_repl_offset:1718
slave_repl_offset:1718
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:1
slave0:ip=127.0.0.1,port=6382,state=online,offset=1718,lag=1
master_failover_state:no-failover
master_replid:8b9acbd5b3737e524d64c2dfb6ac4c9022439b8e
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1718
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:1718

在第二级从节点(Slave2)上查看复制状态:

$ redis-cli -p 6382 info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6381
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_read_repl_offset:1788
slave_repl_offset:1788
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:8b9acbd5b3737e524d64c2dfb6ac4c9022439b8e
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1788
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1065
repl_backlog_histlen:724

这时我们对Master写入一个key,两个Slave是可以访问到的,但是Slave是不能写入的,只能读。

$ redis-cli -p 6380 set aa bb
OK$ redis-cli -p 6381 get aa
"bb"$ redis-cli -p 6382 get aa
"bb"$ redis-cli -p 6382 set cc dd
(error) READONLY You can't write against a read only replica.

此时如果把Master关掉,Slave1都会报一个如下的错误,Slave2不会报错:

4573:S 16 Apr 2025 14:36:38.340 * Connecting to MASTER 127.0.0.1:6380
4573:S 16 Apr 2025 14:36:38.340 * MASTER <-> REPLICA sync started
4573:S 16 Apr 2025 14:36:38.340 # Error condition on socket for SYNC: Connection refused

此时Slave1和Slave2的数据还是可以读的(提供读服务):

$ redis-cli -p 6381 get aa
"bb"$ redis-cli -p 6382 get aa
"bb"

使用主从复制模式,如果Master挂了,需要人工手动指定其中一个Slave升为Master,这里我把6381升为Master:

$ redis-cli -p 6381 REPLICAOF no one

然后Slave1的日志就会打印,Master模式开启:

4573:M 16 Apr 2025 14:41:24.908 * Discarding previously cached master state.
4573:M 16 Apr 2025 14:41:24.909 # Setting secondary replication ID to 8b9acbd5b3737e524d64c2dfb6ac4c9022439b8e, valid up to offset: 1971. New replication ID is e21f3798a676bb852f0b9a5ce73344b4eef57963
4573:M 16 Apr 2025 14:41:24.909 * MASTER MODE enabled (user request from 'id=248 addr=127.0.0.1:36272 laddr=127.0.0.1:6381 fd=8 name= age=0 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=36 qbuf-free=40918 argv-mem=14 obl=0 oll=0 omem=0 tot-mem=61478 events=r cmd=replicaof user=default redir=-1')

这样原来的Slave1也就是新的Master又可以对外提供写服务了:

$ redis-cli -p 6381 set xx oo
OK$ redis-cli -p 6381 get xx
"oo"$ redis-cli -p 6382 get xx
"oo"

核心配置参数详解

主节点相关

# 从节点连接主节点的密码
masterauth "password"
# 主节点自身密码
requirepass "password"# 复制积压缓冲区大小(默认1MB,建议根据数据量调整)
# 主节点将最近的写命令存入缓冲区,从节点断线重连后从中恢复同步,避免全量复制。
# 若网络不稳定或数据量大,增大repl-backlog-size(如256MB~1GB)。
repl-backlog-size 256mb# 缓冲区保存时间(秒,超时后释放)
repl-backlog-ttl 3600# 主节点等待从节点ACK确认的超时时间(默认60秒)
# 跨地域部署时,增大repl-timeout避免因高延迟触发超时。
repl-timeout 120# 是否允许从节点写入(默认no,从节点应只读)
# 若从节点需临时写入测试数据,可设为no(不推荐生产环境)。
replica-read-only yes# 是否启用无盘同步(适用于磁盘IO慢的场景)
# 主节点磁盘性能差时,启用repl-diskless-sync直接通过内存传输RDB文件。
# Disk-backed:master先将数据存在RDB文件并保存到磁盘上,再发送给slave
# Diskless:master直接在内存中生成RDB文件并通过socket发送给slave
repl-diskless-sync yes# 无盘同步等待时间(等待更多从节点连接后批量同步)
# 若从节点数量多,设置repl-diskless-sync-delay合并同步请求。
repl-diskless-sync-delay 5# 主从断开时是否返回旧数据
replica-serve-stale-data yes# 复制缓冲区限制
client-output-buffer-limit replica 256mb 64mb 60  

从节点相关

# 指定主节点IP和端口
replicaof 192.168.1.100 6379# 主节点密码(需与主节点requirepass一致)
masterauth your_master_password# 断线重试间隔(默认10秒,指数退避)
# 频繁断连时,缩短 repl-ping-replica-period 加快心跳检测。
repl-ping-replica-period 10# 是否开启增量复制(默认yes)
# 若主从数据差异大,从节点会触发全量同步(发送RDB文件)。
repl-diskless-load disabled# 从节点同步后是否清空旧数据(默认yes)
# 允许从节点在同步期间继续响应旧数据查询。
replica-serve-stale-data yes# 主节点压缩数据后发送(节省带宽,消耗CPU)
repl-diskless-sync-enabled yes
repl-diskless-sync-max-bitmap-size 64mb# 从节点复制延迟阈值(单位秒,超时触发告警)
# 最少要有1个slave写数据,否则master停止写请求
min-replicas-to-write 1
# 作用:主节点仅在至少N个从节点延迟小于阈值时才接受写请求(类似半同步)。
# # slave延迟超过10s,master停止写请求
min-replicas-max-lag 10

主从复制的改进与缺点

主从复制对单机模式的改进:

  • 故障恢复与高可用性:从节点可作为主节点的冷备或热备(需配合哨兵Sentinel等监控工具),主节点宕机后可晋升新主,降低系统不可用时间。

  • 读写分离提升性能:写请求由主节点处理,读请求分发到多个从节点,充分利用多节点资源,显著提升读吞吐量。

  • 数据冗余与备份:主从节点存储相同副本,即使主节点数据丢失,仍可通过从节点恢复,降低数据风险。

  • 动态扩展能力:根据业务增长灵活添加从节点,突破单机内存容量限制(需配合集群模式完全解决)。

主从复制的限制与注意事项:

  • 异步复制的数据一致性:默认异步复制下,主从数据可能存在短暂延迟(秒级),无法实现强一致性。

  • 写操作仍受主节点单点限制:写压力仍集中在主节点,需通过分片(Cluster)解耦。

  • 故障切换复杂度:主节点故障需依赖额外组件(如 Sentinel)实现自动切换,否则需人工干预。

主从复制的原理

类型同步方式数据一致性性能影响
全量复制首次连接时强一致高IO压力
部分复制断线重连后最终一致低资源消耗

全量复制的触发条件

  • 首次建立主从关系:从节点首次执行REPLICAOF命令连接主节点。
  • 数据差异过大:从节点落后主节点太多(超出复制积压缓冲区范围)。
  • 复制ID不匹配:主节点重启导致复制ID变更,从节点无法增量同步。

全量复制的完整流程

部分复制的触发条件

  • 主从节点的复制ID一致
  • 从节点的复制偏移量仍在主节点的复制积压缓冲区内。

部分复制的完整流程

相关文章:

  • 程序员学英文之Shipment Claim 运输和索赔
  • Node.js学习
  • Vite/Rollup 模块热更新
  • Python内置函数---bytes()
  • MySQL基础增删改
  • CDN加速http请求
  • 百万点数组下memset、memcpy与for循环效率对比及原理分析
  • 【大模型与AIGC深度解析】从核心概念到行业应用
  • Python实现孔填充与坐标转换
  • 网络编程——通信三要素
  • GitLab_密钥生成(SSH-key)
  • 第4天:Linux开发环境搭建
  • 【JavaScript】详讲运算符--算术运算符
  • 时间自动填写——电子表格公式的遗憾(DeepSeek)
  • 品融电商:领航食品类目全域代运营,打造品牌增长新引擎
  • EasySearch 服务昨天还好好的,为什么今天突然访问不了了?
  • Java面试题汇总
  • FI固定资产折旧码的功能用途及其配置介绍
  • 【CSS】层叠,优先级与继承(三):超详细继承知识点
  • 推荐系统排序阶段核心要点:多目标排序模型详解
  • 杨靖︱“一笔糊涂账”:博马舍与美国革命
  • 中海宏洋集团4.17亿元竞得浙江绍兴宅地,溢价率20.87%
  • 禾赛:车载激光雷达走向标配,核心能力可在机器人领域复用
  • 洛阳白马寺内的狄仁杰墓挂上公示牌争论尘埃落定?瀍河区文旅局称已确认
  • 亚振家居半年内第二次筹划变更控制权:控股股东正与收购方商谈交易核心条款
  • 跨市调任:李强已任河北唐山市检察院党组书记