我们项目最近从Redis 6.2升级到了7.2,本以为是个平滑升级,结果踩了不少坑。有些是新特性带来的,有些是兼容性问题,还有些是性能方面的。

这篇文章记录一下升级过程中遇到的各种问题和解决方案,如果你也在考虑升级Redis 7.2,希望能帮你少走点弯路。

升级兼容性的坑

第一个坑是升级兼容性。

Redis 7.0开始引入了很多不兼容的变化,7.2又加了一些。我们从6.2直接升到7.2,跨度比较大,遇到了不少兼容性问题。

第一个问题是配置文件的变化。Redis 7.0废弃了一些旧的配置项,比如rename-command的某些用法,还有一些安全相关的配置。我们的配置文件里用了几个废弃的配置,升级之后Redis启动报错,查了半天才发现是配置项不支持了。

第二个问题是RDB文件格式的变化。Redis 7.0用了新的RDB格式,虽然兼容旧格式的读取,但旧版本读不了新版本的RDB。我们升级的时候做了主从切换,结果从节点还是旧版本,读不了主节点的RDB,主从同步失败。后来只能先把从节点也升级,再做同步。

第三个问题是AOF的变化。Redis 7.0默认用了新的AOF格式,支持多文件AOF。我们的备份脚本是按旧的AOF格式写的,升级之后备份出了问题,恢复的时候数据不对。后来改了备份脚本,用redis-cli的aof相关命令来处理。

第四个问题是客户端库的兼容性。我们用的一些老版本的Redis客户端库,不支持Redis 7.2的某些新命令和新特性。比如我们用的一个Java客户端,升级之后连接Redis 7.2报协议错误,最后只能升级客户端库到最新版本。

新特性的坑

Redis 7.2加了不少新特性,用起来很爽,但也有一些坑。

第一个坑是Functions。Redis 7.0引入了Functions,用来替代Lua脚本,7.2又做了增强。Functions比Lua脚本更好用,支持持久化、复制、版本管理。但我们在迁移Lua脚本到Functions的时候遇到了问题,有些Lua的写法在Functions里不支持,比如某些全局变量的用法。花了不少时间重写脚本。

第二个坑是Sharded Pub/Sub。Redis 7.0引入了分片发布订阅,7.2做了优化。这个特性在集群模式下很好用,消息只在相关分片之间传播,不会广播到所有节点。但我们用的时候发现,某些客户端库不支持Sharded Pub/Sub,只能用普通的Pub/Sub,性能上不去。

第三个坑是ACL的变化。Redis 7.2对ACL做了增强,支持更细粒度的权限控制。但我们的旧用户权限配置在升级之后出了问题,有些命令突然没有权限了。排查之后发现是ACL的默认权限变了,某些命令需要显式授权。最后重新配置了所有用户的权限。

第四个坑是集群模式的变化。Redis 7.2对集群做了一些优化,比如更快的故障转移、更好的槽位迁移。但我们在升级的时候发现,集群节点之间的通信协议变了,旧版本节点和新版本节点不能混合组网。只能一次性把所有节点都升级,中间有短暂的服务不可用。

性能方面的坑

Redis 7.2在性能上有不少优化,但也有一些坑。

第一个坑是内存使用的变化。Redis 7.2对内存分配器做了调整,某些数据结构的内存占用变了。我们升级之后发现,同样的数据,内存占用比6.2高了约10%。排查之后发现是新的listpack编码方式导致的,某些小列表的内存占用反而增加了。最后调整了listpack的配置参数,内存占用才降下来。

第二个坑是延迟波动。Redis 7.2的某些后台任务,比如AOF重写、RDB快照,对主线程的影响和旧版本不一样。我们升级之后发现,在AOF重写的时候,延迟会有短暂的飙升,影响了某些对延迟敏感的业务。后来调整了AOF重写的触发条件,避开业务高峰期,才解决了这个问题。

第三个坑是大key处理。Redis 7.2对大key的删除做了优化,用异步删除代替同步删除,避免阻塞主线程。但我们有个业务依赖了删除的同步性,删除之后立刻查询,期望查不到。升级之后变成异步删除,删除之后立刻查还能查到,导致业务逻辑出错。最后只能在业务代码里加了延迟,或者用UNLINK代替DEL。

第四个坑是连接池的问题。Redis 7.2对连接管理做了一些调整,空闲连接的超时时间变了。我们的连接池配置是按旧版本调的,升级之后经常出现连接超时或者连接被断开的情况。后来调整了连接池的参数,增加了心跳检测,才稳定下来。

数据安全的坑

数据安全是Redis最关键的部分,升级的时候特别小心,但还是踩了坑。

第一个坑是持久化的变化。Redis 7.2的RDB和AOF都有变化,我们的备份脚本没有及时更新,导致备份的数据恢复之后有问题。有一次做灾备演练,用备份的数据恢复,结果发现少了几个小时的数据,吓出一身冷汗。后来重新写了备份脚本,并且定期做恢复演练,确保备份可用。

第二个坑是主从同步的问题。Redis 7.2的主从同步协议有变化,我们在做主从切换的时候,从节点同步数据花了很长时间,期间服务不可用。排查之后发现是新的同步机制在某些情况下会全量同步,而不是增量同步。最后调整了主从配置,用了psync2协议,同步速度才快起来。

第三个坑是集群迁移的问题。我们在做集群槽位迁移的时候,发现迁移速度比旧版本慢了很多,而且迁移过程中某些命令会报错。查了文档才知道,Redis 7.2的迁移机制变了,需要用新的迁移命令,旧的迁移方式虽然还支持但效率低。最后换成了新的迁移命令,问题解决。

第四个坑是过期key的处理。Redis 7.2对过期key的删除策略做了调整,惰性删除和定期删除的比例变了。我们有个业务用了大量带过期时间的key,升级之后发现内存占用波动很大,有时候过期key没有及时删除,内存占用飙升。后来调整了过期删除的配置参数,增加了定期删除的频率,才稳定下来。

监控和运维的坑

升级之后,监控和运维也遇到了一些问题。

第一个坑是监控指标的变化。Redis 7.2加了很多新的监控指标,同时有些旧指标的含义变了。我们的监控系统是按旧版本的指标做的,升级之后有些监控项不准了,甚至报错。花了不少时间更新监控模板,适配新的指标。

第二个坑是日志格式的变化。Redis 7.2的日志格式做了调整,某些日志的级别和内容变了。我们的日志收集系统是按旧格式解析的,升级之后很多日志解析失败,告警也不准了。后来更新了日志解析规则,才恢复正常。

第三个坑是慢查询的变化。Redis 7.2对慢查询日志做了增强,记录了更多信息。但我们的慢查询分析工具是按旧格式写的,升级之后解析不了新的慢查询日志。只能升级工具,或者自己写脚本解析。

第四个坑是配置管理的问题。Redis 7.2的配置项比6.2多了很多,我们的配置管理系统没有及时更新,导致某些新配置项无法通过配置中心下发。最后更新了配置管理的模板,支持新的配置项。

一些建议

踩了这么多坑,总结了一些升级建议。

第一,升级之前一定要读release notes。Redis的release notes写得很详细,每个不兼容的变化都有说明。花时间读一遍,能避免很多坑。我们最开始就是没仔细读,升级之后才发现很多变化。

第二,先在测试环境验证。不要直接在生产环境升级,先在测试环境跑一段时间,看看有没有性能问题、兼容性问题。我们在测试环境跑了一周,发现了好几个问题,修好了才上的生产。

第三,做好备份和回滚方案。升级之前一定要做完整的备份,并且准备好回滚方案。万一升级之后出了问题,能快速回滚到旧版本。我们就准备了回滚脚本,虽然最后没用上,但有备无患。

第四,逐步升级,不要一次性全量。如果是集群模式,可以先升级一个节点,观察一段时间,没问题再升级其他节点。如果是主从模式,可以先升级从节点,切换之后再升级旧主节点。这样风险更小。

第五,关注社区反馈。Redis升级之后,社区里会有很多人分享遇到的问题和解决方案。多关注GitHub issue、邮件列表、微信群,能提前知道很多坑。

写在最后

Redis 7.2是一个很不错的版本,新特性很实用,性能也有提升。但升级的时候还是要小心,特别是从6.x直接升到7.x,跨度比较大,可能会遇到各种各样的问题。

总的来说,升级Redis 7.2是值得的。Functions、Sharded Pub/Sub、增强的ACL这些新特性能解决很多旧版本的痛点,性能和稳定性也有提升。只要做好充分的准备,升级过程还是比较顺利的。

希望这篇文章能帮到正在考虑升级Redis 7.2的你。如果遇到了文章里没提到的问题,欢迎交流。