前两天一个同事跑过来找我说手上还有几台三年的 Redis 5.0 服务器每天跑着好好的但安全通告隔三差五就提醒有 CVE问我怎么在 Linux 上升级到 7.x 比较稳。我跟他讲的第一句话是先别急着敲更新命令。Redis 升级在 Linux 上看起来就是换一个二进制文件的事但真做起来备份策略、配置兼容、主从升级顺序、回滚预案每一步都有讲究搞错一步轻则服务起不来重则直接丢数据或者把主从架构搞出全量重同步。这篇文章我就把 Linux 上 Redis 升级的完整思路和实战过程写一遍升级前要查什么、三条升级路线怎么选、源码编译怎么操作、升级后怎么验证和回滚以及在真实环境里踩过的几个坑。1. 升级Redis前先想清楚这次升级到底要解决什么1.1 老版本不是跑着没事安全漏洞和性能瓶颈往往一起来很多团队对 Redis 的态度是能跑就不动这个心态可以理解但拖着不升的代价往往比你想象的大。一个是安全问题Redis 历史上出过不少与 Lua 沙箱、网络协议解析相关的漏洞官方只维护最近几个大版本老版本过了维护期之后即使出了严重 CVE也不会再有补丁等于把敏感数据暴露在风险里。另一个是性能问题Redis 6.0 引入了 IO 多线程写命令和多实例场景下的吞吐量提升非常明显Redis 7.0 重做了 AOF 和 RDB 的快照机制对大 key 和重写场景的优化很大。我见过有的业务在 5.0 上撑到上万 QPS 就 CPU 打满升到 6.2 之后同样压力 CPU 降了三成这不是玄学是多线程 IO 实打实的效果。1.2 大版本之间到底差了什么在决定升级路线之前先把版本差异看清楚。这里列一张我在团队内部经常贴的对照表版本核心变化升级时最需要注意的点5.x引入 Streams 数据类型没有 ACL任何用户都是全权限6.xACL 权限体系、RESP3 协议、IO 多线程配置中新增 aclfile、io-threads 等指令6.2内存管理改进、阻塞命令优化仓库源里的包可能停留在旧小版本升级要看清版本号7.xFunctions 服务端脚本、AOF 与 RDB 机制重写二进制和持久化文件格式均有变化回滚要谨慎这个表格不用背重点是理解一件事跨大版本升级时除了命令本身还有配置语义和持久化格式两个隐藏雷区。比如 Redis 6.0 开始引入 ACL默认用户和 requirepass 的关系跟 5.x 不一样Redis 7.x 写出来的 RDB 文件老版本不一定能读得回去。这些细节如果不提前处理升级完成的那一瞬间就是故障开始的那一刻。1.3 哪些环境必须马上升哪些可以再等等我一般把升级的判断分成三档。必须马上升的服务暴露在公网或者不可信网络、业务在过等保或安全审计、已经在使用官方宣布 EOL 的版本、或者你已经踩到了某个已公开 CVE 的坑。建议尽快升的使用 5.x 或 6.0 且打算用 ACL 收紧权限、主从或集群规模扩大后明显感觉到单实例瓶颈、需要用到新版本才有的数据类型或命令。可以再等等的纯内网、低流量、上线三年来没出过事、而且短期内没有人手去做完整验证和回滚演练的。最后一种我碰到过不少我的建议是即便如此也先把手动升级流程文档化把备份脚本和回滚步骤准备好等窗口期出现时能直接动手而不是临时查资料。2. 升级前的硬性检查备份、部署形态、配置文件缺一不可2.1 先摸清家底版本、部署方式、数据量三件套任何升级操作前第一步永远是搞清楚现在到底跑的是什么。我会依次执行这几条命令# 看服务端版本 redis-server --version # 看运行实例的版本和启动信息 redis-cli -p 6379 info server # 看进程启动参数确认配置文件路径和数据目录 ps aux | grep redis-server # 看当前数据量 redis-cli -p 6379 dbsize redis-cli -p 6379 info memory这里有个很容易忽略的点redis-server --version显示的版本和实际运行实例的版本不一定一致。有的机器上装过多个 RedisPATH 里的是新版本但 systemd 服务调用的却是旧路径。所以一定要以redis-cli info server里的redis_version为准再配合ps确认启动参数里的配置文件路径。部署形态同样要在这一步确认清楚是单机、主从、哨兵还是 Redis Cluster不同形态的升级顺序完全不同我放在后面专门讲。2.2 备份不是 copy 一个 rdb 就完事备份是升级里最不能省的一步但很多人对 Redis 备份的理解就是把 dump.rdb 拷贝一份这在很多场景下是不够的。完整做法分四步触发一次持久化保证最新数据落盘。执行redis-cli bgsave如果是纯 AOF 模式执行redis-cli bgrewriteaof等命令返回 OK 后用info persistence确认 rdb_bgsave_in_progress 为 0。备份数据文件。把数据目录下的 dump.rdb、AOF 相关文件完整复制到一个安全位置最好用 tar 打包并带时间戳。备份整个数据目录和配置文件。配置文件、pidfile、日志路径都要记录回滚时一个都不能少。验证备份可用。这一步最容易被跳过把备份文件恢复到一台临时目录用临时端口把新实例启起来确认dbsize跟线上一致再关掉。如果你用的是 Linux 下的常规目录我建议在备份完数据文件之后再把整个 Redis 安装目录和使用到的 systemd unit 文件也拷贝一份。这样回滚时不仅数据能找回旧服务和旧配置也能完整恢复不用靠记忆重新拼。2.3 配置文件迁移是个细活Redis 的配置兼容性总体不错但跨大版本时还是会遇到旧配置项被废弃、默认值变化、新版本加了语义不同的指令。我的做法不是直接拿旧 redis.conf 去启动新版本而是先做一次影子配置验证先下载新版本的 redis.conf 作为底版把旧配置文件里所有非默认项逐条对比迁移过去。比如原来设置的 maxmemory、maxmemory-policy、appendonly、save 策略、bind、protected-mode 这些每条都要确认在新版本里还存在、语义没变。如果旧配置里有requirepass6.0 之后要清楚它实际设置的是默认 user 的密码跟 ACL 体系是共存的不是 5.x 里那个独立的全局密码。对于CONFIG REWRITE自动生成的配置如果老配置文件是通过这个命令写出来的里面可能会有平台特有的路径迁移时要顺手改掉。把整理好的新配置文件放到一个新路径比如 /etc/redis/redis-7.conf先用新二进制加临时端口启动一次观察日志有没有Bad directive或者警告。有些旧指令新版本只是不识别但不会让进程退出这种隐患要在试运行阶段就筛出来。3. 三种升级路线怎么选包管理器、源码编译、容器镜像3.1 包管理器适合版本差距小、无自定义编译选项的场景在 Linux 上用包管理器升级是最省事的方式。Debian/Ubuntu 系是apt-get install redis-serverRHEL/CentOS 系是yum update redis或dnf upgrade redis。但这里有个痛点发行版仓库的 Redis 版本通常滞后官方很多。比如 Ubuntu 20.04 自带的是 5.0.7CentOS 8 默认模块流也只是 5.x/6.x 的水平你用 apt 升一个版本可能只是在小版本里打转根本到不了 7.x。所以我的建议是只有升级跨度在一个大版本以内比如 6.2 升 6.2 的补丁版或者对版本要求不敏感才优先走包管理器如果你想要官方最新的 7.x包管理器大概率帮不上忙。3.2 源码编译最麻烦但生产环境我反而推荐源码编译看起来麻烦但在生产服务器上我通常最推荐原因有三个。第一是版本完全可控官方 release 包想装哪个就装哪个不依赖仓库维护节奏。第二是安装路径可控可以装到 /usr/local/redis 这种独立目录跟系统自带的旧版本互不干扰升级切换时改个软链接或者改下 systemd 的 ExecStart 就行。第三是如果有自定义编译参数比如开启某些内存分配器特性只有源码方式能精确控制。缺点也很明显需要 gcc、make 等工具链编译耗时而且后续的二进制升级都要自己管理。不过对于一个长期由运维或 SRE 负责的线上服务这些成本是一次性的后面每次升级都会受益。3.3 Docker 容器本来就在容器里就继续在容器里如果你的 Redis 本来就是 Docker 部署的那升级逻辑就变成了镜像替换docker pull redis:7.2.4然后用新镜像重新起容器数据目录通过 volume 挂载不变。这个方式的优势是回滚极快——旧镜像还在本地出问题docker run一个旧镜像就能恢复。要注意的点主要是三个一是容器版本标签官方 redis 镜像的latest不适合生产一定要钉到明确的版本号二是数据卷路径和权限Redis 容器默认用 redis 用户运行挂载目录的属主和权限对了容器才能写三是网络模式和服务发现如果其他服务通过固定的容器 IP 或 service 名连接 Redis换容器的时候要确保网络配置不变。我个人在纯容器环境里升级 Redis体验确实比物理机舒服很多配置和数据分离得很干净。4. 源码编译方式完整实操从下载到平滑切换4.1 编译前的依赖准备以官方源码包为例先确认机器上有基础工具链。Debian/Ubuntu 执行apt-get install -y build-essential tclCentOS/RHEL 执行yum groupinstall -y Development Tools。这里tcl是跑官方测试套件用的如果是生产环境只想快速编译不跑make test可以省略但我建议不要省编译完顺手跑一遍测试能提前发现当前平台上的编译异常。另外如果你的系统比较老gcc 版本过低编译 Redis 7.x 时可能会遇到兼容性报错这种情况优先升级 gcc或者在 configure 阶段按官方文档关闭对应优化选项不要硬着头皮改源码。4.2 编译安装的完整命令和二进制替换策略# 下载并解压 cd /opt wget https://download.redis.io/releases/redis-7.2.4.tar.gz tar xzf redis-7.2.4.tar.gz cd redis-7.2.4 # 编译-j 参数让多核并行加速 make -j$(nproc) # 可选跑一遍官方测试 make test # 安装到独立目录 make install PREFIX/usr/local/redisPREFIX参数决定了最终二进制落在哪。装完之后/usr/local/redis/bin下会有 redis-server、redis-cli、redis-benchmark 等工具。这里我强烈建议保留旧二进制不要直接覆盖先把系统里正在用的旧二进制复制一份到带版本号的文件名再把新的拷贝过去。比如cp -a /usr/local/bin/redis-server /usr/local/bin/redis-server-6.0.16.bak cp -a /usr/local/bin/redis-cli /usr/local/bin/redis-cli-6.0.16.bak cp -a /usr/local/redis/bin/redis-server /usr/local/bin/redis-server cp -a /usr/local/redis/bin/redis-cli /usr/local/bin/redis-cli这样即使你后续忘记配置软链接也能在 /usr/local/bin 下看到新版本文件并且旧的还在原地。4.3 新版本先做影子试运行再切换拿到新二进制后不要直接替换正在跑的实例。我会先做一次影子试运行把备份出来的数据目录复制一份用新二进制加临时端口启动加载同一份迁移后的配置文件把 port 改成 6400dir 指向临时目录然后做几件验证/usr/local/redis/bin/redis-server /etc/redis/redis-7.conf \ --port 6400 --dir /tmp/redis-shadow-data --daemonize yes redis-cli -p 6400 ping redis-cli -p 6400 dbsize redis-cli -p 6400 info server | grep redis_version redis-cli -p 6400 info persistence如果 dbsize 和老实例一致、持久化状态正常、日志没有异常报错再对热点 key 做几个抽样命令比如用type、ttl、memory usage查看不同数据类型的 key确认字符串、Hash、List、Set、ZSet 这些常见数据类型都正常读取。这一步相当于给升级做了一次彩排所有问题在这里暴露的成本是最低的。我自己每次升级都会跑这个环节它帮我筛出过两次配置文件里的隐蔽问题。4.4 正式切换优雅关停、换二进制、重启影子试运行通过后就可以正式切换了。顺序是这样的# 1. 优雅关停旧实例save 参数会让最后一次持久化完成 redis-cli -p 6379 -a yourpassword shutdown save # 2. 确认进程已经退出 ps aux | grep redis-server # 3. 用新二进制启动 systemctl start redis-server # 如果服务没有托管在 systemd则直接后台启动 # /usr/local/bin/redis-server /etc/redis/redis-7.conf --daemonize yes这里要注意shutdown save虽然方便但如果你担心新老版本持久化格式不兼容可以在关停前手动再做一次bgsave并把生成的文件复制走然后关停时用shutdown nosave避免新格式的 RDB 覆盖掉你验证过的旧格式备份。具体选哪个取决于你是不是做好了回滚预案这个我在下一节展开。5. 新版本起来了别急着走升级后的完整验证清单5.1 基础指标先看这几个升级完成后我建议按这个顺序做快速健康检查。第一步redis-cli ping是否返回 PONG第二步info server确认redis_version已经是新版本第三步info memory看used_memory_human是否和升级前量级一致如果内存突然暴涨或暴跌先检查是不是持久化加载或碎片整理的问题第四步看connected_clients是否恢复到了升级前的数量。这里有一个容易被忽略的点重启后uptime_in_seconds会归零别把这个当成异常但total_connections_received、keyspace_hits等计数器也是一样会重置的所以升级前后对比基线最好在升级前提前记录一份info all的输出文件升级后再对照。5.2 数据与业务功能验证基础指标没问题再深入一层验证业务数据。我的标准动作是dbsize对比升级前记录确认 key 总量没有明显增减。从业务侧挑选几类有代表性的 key执行type、ttl、get或hgetall确认数据类型和值都能正常读取。如果业务用了 Set 做分布式锁、用 List 做消息队列、用 Stream 做事件流每个类型都要至少跑一条写读验证。分布式锁这种依赖过期时间的场景特别要确认新版本的过期策略没有变化。检查info replication主库看role:master和从库连接状态从库看master_link_status:up确认主从关系在升级后依然健康。执行redis-cli --latency观察延迟分布跟升级前对比正常情况下平均延迟和标准差都不应该出现数量级变化。如果以上都正常我才会认为这次升级在业务层面是成功的。这里多提一句如果你用的是 Redis Cluster升级后还要用redis-cli --cluster check做一遍集群健康检查确认 slot 分布正常、节点间连接没问题。5.3 回滚预案出问题怎么退回老版本升级最忌讳的是没有回滚预案就动手。Redis 7.x 写出的 RDB 文件老版本 Redis 可能直接无法加载所以回滚不能简单理解成把旧二进制换回来启动就行。正确的回滚步骤是用redis-cli shutdown nosave关停新实例避免它再写一份新格式的持久化文件。删除或移走升级过程中被修改的数据目录把升级前备份的数据目录原样放回。换回旧二进制用升级前的旧配置文件启动。用info server确认版本回到旧版dbsize和升级前一致。这个流程依赖的正是我在前面反复强调的升级前完整备份。所以我在线上做升级时备份目录、旧二进制备份、旧配置文件三方都在回滚才敢说是有把握的。如果你的数据结构简单、数据量小也可以考虑用redis-cli --rdb导出全量数据做异地备份回滚时直接恢复但这种方式对大数据量不友好还是文件级备份更稳。6. 升级过程中那些翻车现场以及对应的排查套路6.1 升级后密码和 ACL 权限报错从 5.x 跨到 6.x 之后的第一个常见翻车点是认证。Redis 6.0 引入了 ACL 体系requirepass的语义变成了设置 default 用户的密码。在只有 requirepass 的场景下升级后一般还能正常登录但只要你的旧配置里同时存在其他认证相关设置或者升级过程中执行过CONFIG REWRITE就可能出现客户端报NOAUTH或WRONGPASS而服务端日志里又没有明显异常。排查思路是redis-cli不带密码连上去执行ACL LIST看看 default 用户的权限和密码状态再用CONFIG GET requirepass确认当前生效的密码是什么。如果和预期不符用CONFIG SET requirepass修正后执行CONFIG REWRITE。这个坑的麻烦之处在于它不报具体错误只能靠对比升级前后的 ACL 输出定位。6.2 配置文件里的旧指令让新版本启动异常第二个翻车点是配置文件兼容性。我在一次 6.2 升 7.0 的时候旧配置里残留了一个很早的slaveof指令新版本里叫replicaof虽然为兼容性还保留着旧名字但某些组合写法会触发警告还有几个自定义的rename-command用到了新版本里已经不存在的内部命令。表现是新实例启动后复制关系错乱日志里出现一堆Bad directive警告。排查这类问题最有效的方法是在影子试运行阶段就给新实例加上日志观察用grep -iE warn|error|bad directive把可疑行全部拉出来一条一条对照新版本的 redis.conf 检查。旧指令只要是不影响实际业务的能删就删不要贪图留着应该没事。6.3 主从和集群的升级顺序错了触发同步风暴第三个也是我认为影响最大的坑主从环境里先把主库升了结果从库还是老版本两边版本差距导致复制连接建立失败或者从库加载不了主库发来的新格式 RDB直接进入循环重连严重时触发级联的全量重同步把主库带宽和磁盘 IO 打满。标准做法是先升从库选出要升级的从库升级完成并确认master_link_status:up、延迟正常后再对它执行replicaof no one把它提升为新主库然后把原来的主库降级为从库再升级它。整个过程是逐台滚动完成的任意时刻集群里都至少有一台新版本主库在服务。Redis Cluster 和哨兵模式下的思路也一样一台台逐步推进每升完一台就观察集群状态确认没有 slot 迁移或故障转移事件再动下一台。我踩过这个坑之后现在不管什么环境升级都会先把升级顺序写进操作清单避免现场临场判断。最后再分享一个我自己的习惯每次升级前都会把redis-cli -p 6379 info all的输出、config get *的结果、还有dbsize的值各存一份带日期的快照文件升级后挨个比一遍。这个方法几乎零成本但帮我定位过好几次升级后好像哪里不对的模糊问题。备份到位、顺序正确、验证完整这三条都做到位在 Linux 上升级 Redis 就是一次普通的变更而不是一次冒险。