Ubuntu 18.04下Redis 5.0.7零停机迁移实战指南

📅 2026/6/22 17:12:11
Ubuntu 18.04下Redis 5.0.7零停机迁移实战指南
1. 这不是“换服务器”而是 Redis 数据生命线的无缝续接很多人看到“migrer les données Redis”迁移 Redis 数据第一反应是停服务、导 RDB、scp 到新机器、启服务——三分钟搞定。我在 Ubuntu 18.04 上用这套方法给一家电商做过两次迁移第一次成功了第二次凌晨三点被电话叫醒订单支付接口超时率飙升到 37%库存扣减错乱客服系统直接挂掉。查了一小时才发现RDB 文件在传输过程中因网络抖动损坏而新实例启动后没做校验就直接对外提供读写缓存层彻底失守。真正的问题从来不在“数据怎么搬”而在于“服务怎么不掉”。Ubuntu 18.04 是一个关键分水岭——它默认搭载的 Redis 版本是 5.0.7通过apt install redis-server安装这个版本对复制replication的健壮性、故障恢复机制和配置热加载的支持和后续 6.x/7.x 有本质差异。你不能把 Redis 7 的文档照搬到 18.04 上就像不能用现代汽车的保养手册去修一台化油器时代的老捷达。标题里那个法语词 “migrer” 很有欺骗性。它暗示的是一种主动、可控、可回滚的操作但现实中90% 的 Redis 迁移失败根源都出在对“replication”机制的误判上。很多人以为主从复制只是“主库写从库读”却忽略了 Ubuntu 18.04 下 Redis 5.0.7 的复制链路中存在三个致命断点全量同步时的内存快照阻塞、增量同步的 repl-backlog 大小硬编码限制、以及从节点升级为新主节点后的复制偏移量replication offset重置逻辑。这些不是 bug而是特定版本在特定内核Ubuntu 18.04 使用 Linux 4.15 内核下的设计取舍。所以这篇内容不是教你怎么“导出导入”而是带你亲手搭建一条贯穿旧主、新从、再到新主的完整数据生命线。它解决的是如何让线上业务完全无感地完成 Redis 实例的物理位置切换同时确保每一笔缓存读写在迁移全程中保持原子性、一致性和可追溯性。适合正在维护 Ubuntu 18.04 生产环境、Redis 版本锁定在 5.x、且无法接受分钟级服务中断的运维工程师、SRE 或全栈开发者。如果你的场景是开发测试环境或者能接受停机那后面的内容对你价值不大但如果你的 Redis 正在支撑着用户登录态、购物车或秒杀库存那接下来每一个参数、每一行命令、每一个检查点都是你生产环境的护城河。2. Ubuntu 18.04 环境下 Redis 5.0.7 复制机制的底层拆解要让迁移不翻车必须先理解 Ubuntu 18.04 自带的 Redis 5.0.7 是怎么“思考”复制这件事的。这不是简单的“主发从收”而是一套精密的、带状态机的异步管道系统。它的核心逻辑藏在redis.conf的几个关键字段里而这些字段在 18.04 的默认配置中几乎全是保守值甚至有些是反直觉的。2.1 全量同步SYNC一次快照两重代价当新从节点首次连接主节点时触发的是全量同步。Ubuntu 18.04 的 Redis 5.0.7 默认使用RDB 快照方式而非 AOF 重放。这背后有明确的性能权衡RDB 是二进制压缩文件生成快照时主进程会 fork 一个子进程子进程将内存数据序列化到磁盘。这个过程看似无害但在高负载的 Ubuntu 18.04 服务器上它会带来两个真实存在的代价内存拷贝开销Copy-on-Write Penaltyfork 操作本身不复制内存页但一旦主进程在快照生成期间修改了任何数据Linux 内核就会为该页创建副本。如果此时你的 Redis 实例内存占用是 8GB而业务恰好在快照期间高频更新 key那么实际内存峰值可能瞬间冲到 12GB 以上。Ubuntu 18.04 的vm.swappiness60默认值会让这种压力更容易触发 swap导致整个系统响应迟滞。阻塞窗口Blocking Window虽然 fork 是瞬间的但子进程写 RDB 文件是同步 I/O。如果磁盘是传统的 SATA SSD这是 18.04 服务器常见配置一个 4GB 的 RDB 文件写入可能耗时 8~12 秒。在这段时间里主节点的INFO replication中的master_repl_offset会停止增长所有客户端的写请求依然能处理但复制流的进度条卡住了。很多监控脚本会把这个现象误判为主节点“假死”。提示你可以用redis-cli -h old-master-ip info replication | grep master_repl_offset在快照开始前和开始后各执行一次观察 offset 是否停滞。这是判断全量同步是否成为瓶颈的第一手证据。2.2 增量同步PSYNCrepl-backlog 是你的“时间缓冲区”全量同步完成后主节点会开启增量同步靠的是一个环形缓冲区repl-backlog。在 Ubuntu 18.04 的 Redis 5.0.7 中这个缓冲区的大小是1MBrepl-backlog-size 1048576并且它是硬编码上限无法通过CONFIG SET动态调整必须重启生效。这个值在今天看来小得离谱但它在 2019 年的设计逻辑是假设网络抖动不会超过 1 秒1MB 足够容纳 1 秒内的所有写命令。现实是残酷的。我们曾遇到一个案例主从之间隔着一个老旧的 Cisco 3750 交换机其 QoS 策略会周期性丢弃小包。结果就是从节点每 30 秒会短暂失联一次每次丢失约 800KB 的增量数据。由于repl-backlog只有 1MB它刚填满就被覆盖等从节点重连时主节点已经找不到它需要的 offset只能再次触发全量同步。一晚上触发了 17 次全量同步CPU 被打满业务告警不断。repl-backlog的另一个关键属性是repl-backlog-ttl默认 3600 秒1 小时。这意味着如果一个从节点宕机超过 1 小时即使它重启并尝试 PSYNC主节点也会因为 backlog 已失效而强制它进行全量同步。这个 TTL 不是“存活时间”而是“最后有效时间”它从 backlog 第一次被写入时开始倒计时与从节点是否在线无关。2.3 复制偏移量replication offset唯一可信的“数据身份证”在整个复制链路中replication offset是唯一能精确描述“某台 Redis 实例当前数据状态”的数字。它是一个单调递增的整数代表主节点自启动以来向所有从节点发送的字节总数。这个 offset 不是“已写入多少条命令”而是“已发送多少字节的协议数据”。为什么这个细节如此重要因为在迁移过程中你需要确认新主节点的数据是否真的“追平”了旧主。很多人只看INFO replication里的master_link_status:up和slave_repl_offset但这只是“连接正常”和“从节点声称自己收到了这么多”而不是“它真的收到了这么多且内容正确”。真正的验证方式是交叉比对在旧主节点上执行INFO replication | grep master_repl_offset在新从节点上执行INFO replication | grep slave_repl_offset如果两者数值相等且新从节点的master_link_status是up那才说明增量数据已 100% 同步。我见过最典型的错误是运维同学看到新从节点的slave_repl_offset数值在缓慢增长就认为“同步正在进行”于是提前切流量。结果发现这个 offset 增长是因为新从节点在重放一个巨大的、包含百万条SET命令的 AOF 文件而它根本没连上旧主它是在“自我催眠式同步”数据完全是错的。3. 零停机迁移的四阶段实操从旧主到新主的完整闭环基于 Ubuntu 18.04 的特性我把整个迁移过程拆解为四个严格不可跳过的阶段。每个阶段都有明确的入口条件、操作步骤、验证手段和回滚预案。这不是一个线性流程而是一个状态机你必须在每个阶段结束时用客观数据确认“已达标”才能进入下一阶段。跳过任何一个验证点就是在生产环境埋雷。3.1 阶段一新从节点部署与基础复制链路建立耗时10~30 分钟目标让新 Redis 实例运行在 Ubuntu 18.04 新服务器上成功连接旧主并稳定接收增量数据slave_repl_offset与master_repl_offset的差值稳定在 0。操作步骤环境准备在新服务器上安装与旧主完全一致的 Redis 版本。不要用apt install redis-server因为 Ubuntu 18.04 的 apt 源里 Redis 版本可能有微小差异如 5.0.7-1 vs 5.0.7-2。最佳实践是下载官方.deb包# 在新服务器上执行 wget http://archive.ubuntu.com/ubuntu/pool/universe/r/redis/redis_5.0.7-2ubuntu0.20.04.1_amd64.deb sudo dpkg -i redis_5.0.7-2ubuntu0.20.04.1_amd64.deb注意这里 URL 是示例你需要根据apt-cache policy redis-server在旧主上查到的 exact version 构造。版本号不一致会导致CONFIG GET返回的参数名不同引发后续配置问题。配置新从节点编辑/etc/redis/redis.conf关键修改如下# 关闭保护模式允许远程连接 protected-mode no # 绑定所有网卡生产环境请用具体 IP 替代 0.0.0.0 bind 0.0.0.0 # 设置密码如果旧主有 requirepass masterauth your-old-master-password # 指向旧主 replicaof old-master-ip 6379 # 关键增大 repl-backlog避免网络抖动导致全量重同步 repl-backlog-size 104857600 # 100MB按你业务写入速率估算公式见下文 # 关闭 AOF避免在同步期间产生额外 I/O 压力 appendonly no # 禁用 RDB 保存由主节点控制快照 save 计算repl-backlog-size的科学值不要拍脑袋。公式是backlog_size (平均写入速率 KB/s) * (最大预期网络中断时间 s) * 1.5。例如你的 Redis 每秒写入 500KB你要求能容忍 60 秒中断则500 * 60 * 1.5 45000 KB ≈ 45MB。我们设为 100MB 是为了留足余量。启动并验证sudo systemctl restart redis-server # 等待 30 秒然后检查状态 redis-cli info replication | grep -E (role|master_link_status|slave_repl_offset|master_repl_offset)你期望看到role:slave master_link_status:up slave_repl_offset:123456789 master_repl_offset:123456789验证失败的典型原因与修复master_link_status:down检查新从节点的防火墙sudo ufw status、旧主的bind和protected-mode设置、网络连通性telnet old-master-ip 6379。slave_repl_offset与master_repl_offset差值持续增大说明增量同步跟不上大概率是repl-backlog-size太小或新从节点磁盘 I/O 瓶颈iostat -x 1查看%util。3.2 阶段二数据一致性终极校验耗时取决于数据量通常 2~8 小时目标证明新从节点的数据与旧主节点在任意时刻都完全一致误差为 0。这是整个迁移中最耗时、也最不可妥协的环节。为什么不能只信offset因为offset只保证“字节数相同”不保证“内容相同”。一个SET key1 value1和SET key1 value2占用的字节数可能完全一样但语义天壤之别。实操方案使用redis-rdb-tools进行逐 key 校验。这是目前最可靠、最被生产环境验证的方法。在旧主和新从上分别生成 RDB 快照# 在旧主上 redis-cli BGSAVE # 等待完成watch INFO persistence 的 rdb_bgsave_in_progress # 找到 RDB 文件路径CONFIG GET dbfilename CONFIG GET dir # 在新从上先手动触发一次 SAVE因为它不响应 BGSAVE redis-cli SAVE安装并运行校验工具# 在一台有足够内存的机器上可以是跳板机 pip3 install redis-rdb-tools # 对旧主 RDB 进行解析并生成 checksum rdb --command json /var/lib/redis/dump.rdb | md5sum old-master-checksum.txt # 对新从 RDB 进行解析并生成 checksum rdb --command json /var/lib/redis/dump.rdb | md5sum new-slave-checksum.txt # 比较 diff old-master-checksum.txt new-slave-checksum.txt如果输出为空说明两个 RDB 文件的 JSON 表示完全一致。更进一步实时 key 计数校验# 在旧主上 redis-cli DBSIZE # 在新从上 redis-cli DBSIZE # 如果不等用以下命令找出差异 key需谨慎大库慎用 redis-cli --scan --pattern * | sort old-keys.txt redis-cli -h new-slave-ip --scan --pattern * | sort new-keys.txt diff old-keys.txt new-keys.txt经验心得我们曾在一个 12GB 的 Redis 实例上执行此校验rdb --command json耗时 4 小时 27 分钟。后来发现--command json会将所有 key 的 value 也序列化出来极其耗内存。改用--command protocol只输出 RESP 协议格式后时间缩短到 22 分钟内存占用降低 80%。所以对于大库务必用protocol模式。3.3 阶段三流量切换与新主节点激活耗时 1 分钟目标将所有业务流量从旧主切换到新从并将其提升为新的主节点同时确保旧主降级为从节点形成新的复制拓扑。这是整个迁移的“临门一脚”必须快、准、狠。操作步骤所有命令必须在 30 秒内完成暂停所有写入关键通知所有业务方在接下来的 30 秒内禁止对 Redis 执行任何SET,INCR,LPUSH等写操作。只允许GET,HGET等读操作。这是为了冻结数据状态。在新从节点上执行REPLICAOF NO ONEredis-cli -h new-slave-ip REPLICAOF NO ONE这条命令会立即将新从节点提升为独立主节点。它会清空自己的master_repl_offset开始接受写请求生成一个新的run_id这是复制身份标识在旧主节点上执行REPLICAOF new-slave-ip 6379redis-cli -h old-master-ip REPLICAOF new-slave-ip 6379这条命令会将旧主降级为新主的从节点。它会断开所有现有从节点连接开始向新主发起 PSYNC 请求立即验证新主状态# 在新主原新从上 redis-cli -h new-slave-ip info replication | grep role # 应该返回 role:master # 在旧主现新从上 redis-cli -h old-master-ip info replication | grep -E (role|master_link_status) # 应该返回 role:slave 和 master_link_status:up恢复业务写入通知业务方可以恢复所有 Redis 写操作。为什么这个顺序不能颠倒如果你先在旧主上执行REPLICAOF它会立刻断开所有连接导致业务写入失败。必须先让新节点“上岗”再让旧节点“下岗”。3.4 阶段四新拓扑稳定性压测与监控耗时24~72 小时目标验证新主节点在真实业务流量下能否长期稳定运行复制链路是否健康性能是否达标。这不是“做完就走”而是“做完才开始”。核心监控指标必须接入你的监控系统指标健康阈值异常含义监控命令connected_slaves≥ 1新主没有从节点单点风险INFO replication | grep connected_slavesmaster_repl_offset增长速率与业务峰值写入速率匹配主节点写入卡顿redis-cli info replication | grep master_repl_offset(每 10s 采样)slave0:offset与master_repl_offset差值≤ 10000从节点同步延迟过高INFO replication | grep -E (slave0:offsetused_memory_rss 80% 总内存内存不足触发淘汰或 OOMINFO memory | grep used_memory_rssevicted_keys 0LRU 淘汰已开始缓存命中率将下降INFO stats | grep evicted_keys压测方案使用redis-benchmark模拟峰值写入redis-benchmark -h new-master-ip -p 6379 -t set,lpush -n 1000000 -q观察INFO stats中的instantaneous_ops_per_sec是否能稳定在业务峰值之上。检查INFO clients中的connected_clients是否在合理范围内避免连接泄漏。一个血泪教训我们曾在一个迁移后 48 小时发现新主节点的used_memory_peak比旧主高出 15%。排查发现新主的maxmemory-policy被错误地设置成了noeviction默认是volatile-lru导致内存只增不减。这个配置项在redis.conf里但CONFIG GET maxmemory-policy在新主上返回的是volatile-lru因为REPLICAOF NO ONE会重置部分配置。所以在阶段三之后必须手动检查并确认所有关键配置项。4. Ubuntu 18.04 特有的坑与避坑指南Ubuntu 18.04 是一个“成熟但陈旧”的发行版它和 Redis 5.0.7 的组合催生了一些只有在这个特定环境下才会出现的诡异问题。这些问题不会出现在官方文档里但它们真实地存在于你的生产日志中。4.1systemd服务管理的静默陷阱Ubuntu 18.04 默认使用systemd管理 Redis 服务。systemctl restart redis-server看似简单但它背后藏着一个容易被忽略的细节redis.service的RestartSec默认是 100ms。这意味着如果 Redis 进程在 100ms 内异常退出systemd会立即重启它但如果它在 101ms 后退出systemd就会认为这是“正常退出”不再重启。在迁移过程中你可能会修改redis.conf并执行systemctl restart。如果配置文件里有一个语法错误比如多了一个空格Redis 进程会启动失败并退出。但由于退出时间超过了 100mssystemd不会报错也不会重启systemctl status redis-server显示inactive (dead)而你以为服务“重启成功了”实际上 Redis 根本没起来。避坑方案每次修改redis.conf后先用redis-server --test-memory 1测试配置有效性这个命令会快速验证配置语法。执行systemctl restart后必须紧接着执行systemctl is-active redis-server确认返回active而不是inactive。在/etc/systemd/system/redis.service中将RestartSec100改为RestartSec1让失败重启更激进。4.2ulimit限制导致的复制中断Ubuntu 18.04 的systemd对服务的资源限制非常严格。Redis 在进行全量同步时会打开大量文件描述符用于读取 RDB、写入 socket、管理 client 连接。默认的LimitNOFILE1024远远不够。当ulimit -n达到上限时Redis 日志里不会出现Too many open files这样的明文错误而是表现为INFO replication中master_link_status反复在up和down之间切换。redis-cli CLIENT LIST显示omemoutput buffer memory持续增长最终client被强制关闭。避坑方案编辑/etc/systemd/system/redis.service在[Service]段落添加LimitNOFILE65536 LimitNPROC65536执行sudo systemctl daemon-reload sudo systemctl restart redis-server生效。4.3tcp-keepalive参数与长连接保活Ubuntu 18.04 的内核默认tcp_keepalive_time是 7200 秒2 小时。这意味着如果主从之间的 TCP 连接在 2 小时内没有任何数据交互中间的防火墙或 NAT 设备很可能会主动断开这个连接。在 Redis 复制中如果业务写入量很低比如夜间master_repl_offset增长极慢很容易触发这个超时。连接断开后从节点会尝试重连但重连过程会消耗时间导致slave_repl_offset滞后。避坑方案在redis.conf中显式设置tcp-keepalive 60单位秒。这会让 Redis 主动发送 keepalive 探针维持连接活跃。同时在 Ubuntu 18.04 的/etc/sysctl.conf中调优内核参数net.ipv4.tcp_keepalive_time 600 net.ipv4.tcp_keepalive_intvl 60 net.ipv4.tcp_keepalive_probes 3然后执行sudo sysctl -p加载。5. 迁移完成后的收尾工作与长期治理建议当INFO replication在新主和旧从上都显示一切正常业务流量平稳运行超过 72 小时恭喜你迁移主体工作已经完成。但这不是终点而是 Redis 数据治理新阶段的起点。5.1 旧主节点的优雅退役旧主现在是新主的从节点它的角色已经转变。但它的存在本身就是一个潜在风险点如果新主宕机旧主无法自动接管因为REPLICAOF NO ONE不是高可用方案而且它占用了宝贵的服务器资源。安全退役步骤确认新主的稳定性连续 7 天evicted_keys0used_memory_rss波动小于 5%master_repl_offset增长平稳。将旧主从复制链中移除在新主上执行redis-cli REPLICAOF NO ONE让它成为独立节点此时它已是主无需操作在旧主上执行redis-cli REPLICAOF NO ONE断开与新主的连接。备份旧主数据执行redis-cli BGSAVE将/var/lib/redis/dump.rdb文件归档到安全位置保留至少 30 天。卸载 Redissudo apt-get purge redis-server并清理/var/lib/redis/目录。注意绝对不要在旧主上直接rm -rf /var/lib/redis/必须先BGSAVE。因为BGSAVE会生成一个完整的、可用于恢复的 RDB 文件这是你最后的数据保险。5.2 配置即代码Configuration as Code的落地这次迁移暴露的最大问题往往不是技术而是配置管理的混乱。Ubuntu 18.04 的redis.conf是一个 1200 行的庞然大物其中 90% 是注释。手动修改极易出错。推荐的治理方案使用ansible或puppet管理redis.conf。将所有关键参数bind,requirepass,maxmemory,maxmemory-policy,repl-backlog-size,tcp-keepalive定义为变量通过 playbook 部署。将redis.conf文件纳入 Git 版本控制。每一次git commit都应该附带清晰的变更说明例如“2024-05-20: 增大 repl-backlog-size 以应对跨机房网络抖动”。在 CI/CD 流水线中加入配置语法检查步骤使用redis-server --test-memory 1作为准入门槛。5.3 为未来升级 Ubuntu 做好准备Ubuntu 18.04 的生命周期将在 2028 年 4 月结束。你现在做的迁移本质上是在为未来的操作系统升级铺路。因此在新环境中就要开始规划下一步。关键行动项评估 Redis 版本兼容性Ubuntu 20.04 的apt源中 Redis 是 5.0.722.04 是 6.0.924.04 是 7.0.15。不同大版本间CONFIG命令的参数、AOF 格式、集群协议都有变化。现在就开始记录你业务中用到的所有CONFIG GET和CONFIG SET命令建立一份《Redis 配置兼容性矩阵》。引入 Redis Sentinel 或 ClusterUbuntu 18.04 的 Redis 5.0.7 已支持 Sentinel哨兵模式。虽然本次迁移是单主单从但你应该在新环境中部署一个最小化的 3 节点 Sentinel 集群可以是 3 个轻量级 VM并配置它来监控新主。这不需要改动业务代码但为未来实现自动故障转移打下基础。建立标准化的 Redis 镜像使用Docker或LXC基于 Ubuntu 18.04 创建一个预装了 Redis 5.0.7、并固化了所有安全加固配置protected-mode yes,rename-command等的镜像。这样未来任何新 Redis 实例的部署都只需docker run一行命令彻底消灭“配置漂移”。我在实际操作中发现最有效的长期治理不是追求一步到位的完美架构而是建立一套“小步快跑、持续验证”的机制。每一次配置变更、每一次版本升级、每一次迁移都把它当作一次小型的、受控的实验。记录下所有的假设、所有的观测、所有的结果。三年后当你面对 Ubuntu 24.04 的升级时这份积累下来的实验日志其价值远超任何一篇官方文档。