ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Redis主从复制:从单机到高可用的第一级台阶,解决四大生产难题

Redis主从复制:从单机到高可用的第一级台阶,解决四大生产难题 单机Redis的四个“不够用”主从复制到底解决了什么先说结论一台 Redis 不是不能用而是扛不住生产环境的四个基本要求高可用、读扩展、数据安全、运维窗口。主从复制Master-Replica Replication是 Redis 从“单机玩具”走向“生产可用”的第一级台阶也是后面哨兵Sentinel和集群Cluster的地基。先从场景说起。假设你只用一台 Redis代码里redis-server一启动业务也能跑缓存也能命中好像没什么问题。但真实的生产环境往往会遇到这四种情况第一单点故障。这台 Redis 挂了整个依赖缓存的业务直接熔断数据库瞬间被流量打穿。Redis 本身很快但一台机器、一个进程无法保证 7×24 小时不宕机。进程可能 OOM服务器可能断电硬盘可能损坏网络可能抖动。任何一次意外都是缓存层的整体不可用。第二读压力集中在单实例。Redis 单实例的 QPS 可以到 10 万级别但这是理想情况。实际业务中大量的读请求会集中在热点 key 上比如首页数据、用户会话、商品详情。一台 Redis 扛所有读流量CPU 和网卡都会成为瓶颈。更关键的是读流量往往远大于写流量但一台实例上读写混跑资源互相抢占。第三数据安全依赖 RDB/AOF 持久化但持久化本身有代价。开启 RDB fork 子进程做快照大实例下 fork 会卡顿AOF 文件重写也会带来磁盘和 CPU 开销。更麻烦的是如果只有一台机器硬盘坏了RDB 和 AOF 文件也没了恢复无从谈起。第四运维操作需要停机窗口。升级 Redis 版本、修改配置、执行FLUSHALL、迁移机器单机模式下只能停服操作。业务高峰期动 Redis基本等于自杀。主从复制解决的就是这些问题一台 Master 负责写多台 Replica 负责读和备份Master 挂了Replica 可以顶上数据实时从 Master 同步到 Replica相当于天然多了一份热备份。下面把主从复制的核心能力、部署方式、工作原理、常见坑一次讲清楚。1. 主从复制核心能力速览在开始部署之前先用一张表快速过一遍主从复制的关键信息。这里的“能力项”都是主从复制的通用设计不依赖特定 Linux 发行版或 Redis 版本。能力项说明解决的核心问题单点故障、读压力扩展、数据热备份、运维窗口节点角色一个 Master主节点加多个 Replica从节点复制方向单向复制Master 写到 ReplicaReplica 不能反向写回 Master数据同步模式全量复制RDB 快照 缓冲区和增量复制命令传播读扩展能力读请求可以分发到多个 Replica分担 Master 读压力高可用上限主从本身不提供自动故障转移需要配合 Redis Sentinel支持的部署方式Linux 原生部署、Docker Compose、Windows 开发环境WSL/懒人包是否需要额外组件不需要Redis 内置REPLICAOF命令和配置项对业务代码的影响读写分离后需要区分连接 Master 和连接 Replica 的连接池常见瓶颈网络带宽、全量复制时的 RDB 传输、复制积压缓冲区大小、磁盘写入速度适合场景缓存层读写分离、数据热备、故障转移前置准备、多机房就近读从表里可以看得很清楚主从复制的价值不是“多一台机器这么简单”而是把 Redis 从单点变成了一个可水平扩展读取能力的小集群。但也要注意它不解决写扩展问题也不解决自动故障转移问题。写流量大、需要自动切换的场景要看后面的哨兵和 Cluster。如果你正在准备面试这张表里的“单向复制”“只解决读扩展”“需要配合 Sentinel”这三条是高频考察点。2. 适用场景与使用边界主从复制不是银弹它只解决特定的问题。先看它适合做什么再看它做不了什么避免方向性错误。适合的场景读多写少的业务缓存层。比如商品详情、用户信息、新闻列表。写请求量不大读请求量很大一台 Master 扛不住的流量拆到 2 到 3 台 Replica 上每台压力直接降一半以上。数据热备份。主从模式下Replica 有完整的数据副本。如果 Master 数据损坏可以等待 Replica 的数据继续服务或者将 Replica 提升为 Master。注意“提升”这个动作在纯主从架构下需要人工完成生产上通常用 Sentinel 自动完成。跨机房读部署。在多个机房各放一个 Replica应用连接本机房的 Replica 读取数据。写入仍然走中心机房的 Master这样能降低跨机房读延迟。代价是副本数据存在异步延迟极端情况下可能读到旧数据。发布和运维演练。可以先对 Replica 执行DEBUG SLEEP、CLIENT PAUSE等操作观察对业务的影响再接上正式流量。RDB 快照也可以放到 Replica 上执行避免 fork 对 Master 的影响。不适合的场景写流量高的业务。主从复制只有一份可写数据入口Master所有写命令全部集中在一台实例上。写 QPS 超过单实例上限加 Replica 没有意义。对数据一致性要求极高的场景。Redis 主从复制默认是异步复制Replica 的数据可能比 Master 滞后。如果业务要求“写入后必须立刻读到”主从架构不适合需要引入其他机制。需要自动故障转移的场景。主从架构下 Master 宕机不会自动选出一个新的 Master。如果运维没有及时介入业务写入会直接失败。生产环境至少要上 Sentinel。多个写入口的场景。不要把两台 Redis 互相设置为主从也不要在 Replica 上执行写命令并且期待写操作能同步回 Master。Redis 主从复制是单向的写入 Replica 的数据在下次全量同步时甚至可能被覆盖。从数据安全角度补充一句主从复制不等于数据绝对安全。如果主从部署在同一台物理机硬盘故障时两个实例一起丢数据。多副本要放在不同机器、不同机架、甚至不同机房才是真正的高可用。3. 本地环境准备与前置检查部署主从复制不需要很高的硬件门槛。一般 2 核 4G 内存、20G 磁盘的云主机就能跑一套 Master 2 Replica 的实验环境。如果只是本机学习一台电脑开三个 Redis 实例不同端口完全够用。3.1 操作系统与 Redis 版本主从复制对操作系统没有特殊要求常见选项如下Linux服务器生产推荐CentOS 7/8、Ubuntu 20.04/22.04 均可。macOSbrew install redis后直接使用。Windows官方没有原生 Windows 版本但可以使用 WSL 2、Docker Desktop 或开源移植版本进行学习。生产环境不建议使用 Windows 跑 Redis。Redis 版本建议主从复制本身是非常成熟的功能Redis 3.0 以后都支持REPLICAOF命令。建议使用 Redis 6.x 或 Redis 7.x新版对复制缓冲、增量复制的性能和稳定性都有优化也为后面的 ACL、多线程 IO 等功能留出余地。检查本机是否已安装 Redisredis-server --version如果没安装最快速的方式是 Docker 启动docker pull redis:7.0或者用包管理器安装# Ubuntu / Debian sudo apt update sudo apt install redis-server -y # CentOS / RHEL sudo yum install redis -y3.2 端口规划主从复制实验至少要规划三个端口。按常见惯例我只做端口映射说明实际可以按需调整实例角色默认端口说明Master6379写入口业务主连接Replica 16380读入口分担读流量Replica 26381读入口备份节点3.3 系统参数检查在 Linux 上部署前建议检查两项关键参数# 查看内存和磁盘 free -h df -h # 查看 TCP 连接限制 ulimit -n如果ulimit -n值偏小建议调大文件描述符限制否则在高连接数下 Redis 会报 “Cannot accept a client: too many open files”。3.4 准备配置文件主从复制的配置有两种方式写在配置文件里或者运行时用命令动态设置。建议实验阶段先用命令生产环境用配置文件方便开机自启和统一管理。下面准备三个最小配置示例实际使用需要放到不同目录例如/etc/redis/redis-6379.conf、redis-6380.conf、redis-6381.conf。Master 主节点redis-6379.confport 6379 daemonize no dir /data/redis/6379 logfile /data/redis/6379/redis.log appendonly yes appendfilename appendonly.aofReplica 从节点redis-6380.confport 6380 daemonize no dir /data/redis/6380 logfile /data/redis/6380/redis.log appendonly yes appendfilename appendonly.aof replicaof 127.0.0.1 6379Replica 从节点redis-6381.confport 6381 daemonize no dir /data/redis/6381 logfile /data/redis/6381/redis.log appendonly yes appendfilename appendonly.aof replicaof 127.0.0.1 6379注意replicaof需要写成主机名 端口中间是空格不是冒号。这是新手最容易踩的坑。4. Docker Compose 搭建 Redis 主从复制如果你不想在宿主机上装多个 Redis用 Docker Compose 是最快的方式。新建一个目录比如redis-replication然后创建docker-compose.ymlservices: redis-master: image: redis:7.0 container_name: redis-master command: [redis-server, --port, 6379, --appendonly, yes] ports: - 6379:6379 volumes: - ./master-data:/data redis-replica-1: image: redis:7.0 container_name: redis-replica-1 command: [redis-server, --port, 6380, --replicaof, redis-master, 6379, --appendonly, yes] depends_on: - redis-master ports: - 6380:6380 volumes: - ./replica1-data:/data redis-replica-2: image: redis:7.0 container_name: redis-replica-2 command: [redis-server, --port, 6381, --replicaof, redis-master, 6379, --appendonly, yes] depends_on: - redis-master ports: - 6381:6381 volumes: - ./replica2-data:/data启动docker-compose up -d查看三个容器状态docker-compose ps这三条命令会分别启动 Master6379、Replica 16380、Replica 26381并且自动完成主从关联。Docker 网络内部会自动解析redis-master这个服务名所以不需要填写宿主机的 IP。注意这里把数据目录挂载出来了如果实验完成想清理执行docker-compose down -v会连数据卷一起删除。5. Redis 主从复制的验证流程与效果检查环境起来之后最关键的一步是验证主从关系是否建立成功、数据是否真的能同步。下面是一套完整的验证流程。5.1 查看主从关系状态先进入 Master 容器或直接通过客户端连接 6379 端口redis-cli -p 6379执行127.0.0.1:6379 INFO replication预期输出类似# Replication role:master connected_slaves:2 slave0:ip172.20.0.3,port6380,stateonline,offset98,lag0 slave1:ip172.20.0.4,port6381,stateonline,offset98,lag0再看 Replica 的状态redis-cli -p 6380 127.0.0.1:6380 INFO replication预期输出中的角色应该是role:slave并且master_link_status:up。如果出现master_link_down_after_seconds或者master_link_status:down说明主从之间网络不通或者配置错误。5.2 写入数据并验证同步在 Master 上写入一条数据127.0.0.1:6379 SET user:1001 zhangsan OK到 Replica 上读取127.0.0.1:6380 GET user:1001 zhangsan能读到值说明 RDB 全量复制和后续的增量命令传播都正常。再写一个列表类型127.0.0.1:6379 RPUSH msg:queue hello world redis (integer) 3到 Replica 上确认长度和内容一致重点看偏移量 offset是否持续对齐。主从复制是异步的正常情况下 lag 会在 0 到 1 之间波动。5.3 验证从节点是否可写这是主从复制的关键特性。尝试在 Replica 上写数据127.0.0.1:6380 SET user:1002 lisi (error) READONLY You cant write against a read only replica.这个报错是预期行为。Redis 从节点默认是只读的写不进去。这保证了主从数据方向不会被打乱。如果你确实需要从节点临时可写比如做本地缓存扩展可以启动时加参数--replica-read-only no但生产环境不推荐。5.4 验证主节点宕机后的手动切换模拟 Master 宕机在容器场景下可以执行docker stop redis-master此时访问 Master 端口会失败但 Replica 还在运行读请求不会中断。要恢复写入需要手动提升一个 Replica 为 Masterredis-cli -p 6380 127.0.0.1:6380 REPLICAOF NO ONE OK 127.0.0.1:6380 INFO replication执行REPLICAOF NO ONE后6380 会从 Replica 变成 Master可以接受写入。原来的 Master 恢复后如果需要重新加入要执行redis-cli -p 6379 127.0.0.1:6379 REPLICAOF 127.0.0.1 6380 OK这就是手动故障转移。效率低、需要人介入生产环境不推荐手动操作正确做法是部署 Redis Sentinel。6. Redis 主从复制的原理拆解从全量复制到增量复制验证完功能理解原理很重要。主从复制的原理是面试重点也是排查问题的基础。网上很多资料讲得抽象这里我用一条时间线把复制过程拆开。6.1 第一次全量复制从零开始建副本当 Replica 第一次执行REPLICAOF或者配置了replicaof时Replica 会向 Master 发送PSYNC命令。这个命令带两个参数复制 IDreplid和偏移量offset。如果 Replica 是全新的偏移量是 -1Master 判断需要全量复制。全量复制的三步Master 执行BGSAVE生成 RDB 快照。这个 fork 子进程的操作对 Master 有一定影响大实例下尤其明显。Master 将 RDB 文件发送给 Replica。传输期间 Master 收到的所有写命令会先写入复制积压缓冲区repl_backlog等 RDB 传完之后再补发给 Replica。Replica 清空旧数据加载 RDB 文件然后接收并执行 backlog 中的增量命令追平到最后一条写命令。所以第一次全量复制阶段Replica 的数据是“清空后重建”的。这也是为什么主从复制不能随意加 Replica全量复制高峰期 Master 的磁盘和网络开销都不小。6.2 之后的增量复制命令传播全量复制完成后Replica 的复制状态变成online。之后 Master 每执行一条写命令都会把命令发送给所有已连接的 Replica这个过程叫“命令传播”。Replica 边接收边执行保持和 Master 的最终一致。这套机制下主从之间通过offset来对齐进度。Master 和 Replica 各自维护偏移量如果不一致说明缓存了新命令还没执行完。网络闪断时Replica 会重新连接 Master并带上自己的偏移量。如果偏移量仍在 Master 的 repl_backlog 缓冲范围内就只补发缺失部分如果落后太多错过了 backlog 中的数据就退化回全量复制。6.3 一个常见的坑复制积压缓冲区太小repl-backlog-size默认是 1MB。如果写入量很大Replica 断线几秒钟就落后超过 1MB重连后只能全量复制。频繁的全量复制会拖垮 Master。生产环境建议把repl-backlog-size调大到 64MB 到 256MB并根据峰值写入量评估。6.4 关于主从复制延迟的观察主从延迟可以通过INFO replication中 Replica 的lag字段观察。lag表示 Replica 最后一次与 Master 交互的延迟秒数。正常情况下应该接近 0。如果 lag 持续增大说明 Replica 执行命令跟不上需要检查 Replica 的 CPU、磁盘和网络。7. 资源占用与性能观察主从复制不是“开了就完事”它对资源的消耗可以从三个维度观察。7.1 网络带宽主从复制最大的资源开销是网络。RDB 传输阶段是突发流量一个 5GB 的实例做全量复制网络峰值可能跑到几百 MB/s。日常增量传播阶段每条写命令都会产生一次主到从的发送开销。Replica 数量越多Master 的网卡出站流量越大。7.2 磁盘 IORDB 全量复制时Master 和 Replica 都在做磁盘写入。Replica 在加载 RDB 时还会清空旧数据如果使用 SSD 问题不大机械硬盘下延迟会明显。注意不要在主从同时开启 AOF rewrite 和 RDB BGSAVE 的定时任务错峰执行能明显降低磁盘压力。7.3 CPU 开销Replica 执行与 Master 相同的写命令CPU 开销不会因为“只是备份”而降低。如果业务读多写少Replica 的 CPU 主要消耗在读请求上写多的业务Replica 和 Master 的写入开销基本一致。如果实验环境是笔记本可以打开redis-cli --stat实时观察redis-cli -p 6379 --stat这个命令会每秒刷新一次输出客户端的连接数、内存占用、命令执行次数等。两台终端分别跑 Master 和 Replica就能直观感受到同步流量。8. 常见问题与排查方法主从复制部署简单但问题也不少。下面的表格覆盖了我见过的绝大多数问题。问题现象可能原因排查方式解决方案master_link_status:down网络不通、防火墙拦截、Master 密码不匹配查看 Replica 的日志文件检查主从之间防火墙规则确认requirepass和masterauth配置一致Replica 一直处于wait_bgsave状态Master 正在生成 RDB全量复制未完成查看 Master 的INFO persistence和日志等待 BGSAVE 完成或调低repl-diskless-sync-delayReplica 频繁做全量复制repl-backlog-size太小断线后 offset 超出积压缓冲区查看INFO replication中的 backlog 信息调大repl-backlog-size到 64MB 以上从节点读取不到最新数据主从复制有延迟异步复制导致短暂不一致查看lag字段业务接受短暂延迟对一致性要求高的请求强制走 Master从节点执行写命令报 READONLYReplica 默认为只读查看config get replica-read-only从节点不应写入确认是业务代码误连了从库全量复制时 Master 卡顿BGSAVEfork 子进程导致短时停止响应查看 Master 日志和INFO stats中的 latest_fork_usec使用repl-diskless-sync yes开启无盘复制或错峰同步主从数据不一致主从连接中断时间过长、数据量超过 backlog 容量触发全量同步时 Replica 清理数据对比 Master 和 Replica 的INFO replication中的 offset增大 backlog增加监控必要时重建从节点密码配置后无法建立主从只配置了 Master 的requirepassReplica 没有配置masterauth查看 Replica 日志Replica 配置masterauth password使用与 Master 相同的密码主从建立后看不到数据Replica 加载 RDB 失败或磁盘空间不足查看 Replica 日志中的 error 信息检查磁盘空间删除 Replica 旧数据后重新全量同步下面重点说排查思路。遇到主从问题第一件事不是改配置而是看 Replica 的日志。日志文件位置通常由配置项的logfile指定默认在 Redis 的数据目录下。日志中会直接告诉你原因比如MASTER - REPLICA sync startedFull resync requested by replicaCant get RDB file from mastermaster_link_status down第二步使用redis-cli查看主从关系状态redis-cli -p 6380 INFO replication重点看master_host、master_port、master_link_status、slave_read_only、master_repl_offset这几个字段。第三步用redis-cli -p 6379 CLIENT LIST查看 Replica 是否已经建立 TCP 连接。连接建立了说明网络层没问题没建立优先查防火墙。9. 从主从到哨兵再到集群的演进路线主从复制是 Redis 高可用体系的第一环。很多读者会问有了主从是不是就够了答案是不够。Sentinel哨兵解决的是“自动故障转移”问题。它在主从之上加了一层监控监视 Master 是否存活。当 Master 被判定为客观下线时Sentinel 会从 Replica 中选出一个新的 Master并通知其他 Replica 和新客户端更新连接。主从架构自动切换后业务写入才真正不中断。Redis Cluster 解决的是“数据分片”和“写扩展”问题。Cluster 默认有 16384 个哈希槽每个节点负责一部分槽位。数据写入时按 key 的 CRC16 结果找到对应节点从而把写流量分散到多台机器。Cluster 内置了复制和高可用逻辑每个分片下可以有 Replica比“主从 Sentinel”更适合大规模场景。演进路线可以总结为单机 Redis适合开发、测试、数据量小的内部工具。主从复制适合读多写少、需要热备份、能接受手动切换的场景。主从 哨兵适合生产环境自动故障转移读写分离。Redis Cluster适合数据量大、写流量高、需要水平扩展的场景。从主从复制入手先把数据同步机制和故障切换流程跑通再上哨兵和集群会顺畅很多。10. 最佳实践与使用建议最后给一套工程化建议照着做能省掉很多后面要补的坑。第一连接池要区分读写。主从架构下业务连接必须区分 Master 连接池和 Replica 连接池。写命令、强一致读命令走 Master允许延迟的读命令走 Replica。如果代码只在配置里改一个连接地址起不到任何扩展读的效果。Spring Boot 项目中可以配置两套LettuceConnectionFactory分别指向 Master 和 Replica。第二Replica 数量不要盲目堆。每增加一个 ReplicaMaster 就要多承担一份全量传输和增量传播的开销。读流量不大的时候一台 Replica 足够读流量大优先考虑在业务侧加缓存而不是无限加从库。建议 Replica 不超过 3 台除非有跨机房需求。第三所有实例要加监控。至少监控四个指标主从连接状态、复制延迟lag、repl_backlog 是否溢出、磁盘剩余空间。用 Prometheus Redis Exporter 可以很方便地采集。配置告警阈值时延迟超过 10 秒就要介入排查。第四安全配置不能省。公网环境必须设置requirepassRedis 不推荐直接暴露到公网。主从复制时Replica 上要设置相同密码的masterauth否则认证失败。如果有条件把 Redis 放到内网用安全组或防火墙限制来源 IP。第五配置参数按需调整。最常调的有三个# 复制积压缓冲区建议按峰值写入量评估示例为 128MB repl-backlog-size 128mb # 无盘同步Master 不落盘直接发送 RDB适合大实例全量复制 repl-diskless-sync yes # 无盘同步延迟给多个从节点攒一个 RDB 的时间 repl-diskless-sync-delay 5这些参数在配置文件中修改后需要重启 Redis 才会生效。CONFIG SET可以临时修改部分参数但repl-diskless-sync必须在配置文件中设置后才能验证重启效果。第六主从复制不是备份策略的全部。Replica 上的数据是 Master 的实时副本手动误操作比如FLUSHALL也会同步到 Replica。生产环境还是要定期做 RDB 备份或者 AOF 备份把备份文件放到 Redis 实例所在的机器之外。
返回列表