当前位置:首页 > 问答 > 正文

Redis没设过期策略,数据丢失风险其实挺大,不注意就完蛋了

(来源:某互联网公司技术团队故障复盘报告)我们之前一直觉得Redis就是个大内存缓存,速度快就行,没太在意过期时间这个设置,心想反正服务器内存大,存再多数据也能扛住,结果上个月就出事了,一个用来存放用户临时会话信息的Redis实例,因为从来没设置过过期时间,里面堆积了长达半年的无效用户会话数据,这些数据其实在用户 logout 之后就再也没用过了,但就一直赖在内存里,直到有一天,这个实例的内存被彻底撑满,触发了Redis的默认淘汰机制,它开始随机删除键来腾空间,这一删,就把很多活跃用户的会话也给删掉了,导致大量在线用户突然被踢下线,需要重新登录,投诉电话瞬间被打爆,我们紧急扩容后才暂时缓解,但教训太深刻了,数据不是存进去就一劳永逸的,无效数据就是埋下的雷。

(来源:一位运维工程师的博客分享)还有一种更隐蔽的情况,风险不比内存爆满小,我们有个业务,用Redis的List结构做消息队列,生产者不停地往里面塞任务,消费者从另一边取任务执行,一开始跑得好好的,后来我们发现消费者的处理速度偶尔会跟不上生产速度,队列里就会积压一些消息,这本来正常,但问题是我们没给这些消息设置过期时间,结果有一次,消费者服务因为一个BUG卡死了整整一天,等我们修复好BUG重启服务时,队列里已经堆积了上千万条消息,消费者开始疯狂追赶,由于每条消息都涉及复杂的计算,处理速度很慢,更糟糕的是,很多消息的生产时间已经是24小时以前了,对应的业务场景早都过期了(比如一个限时优惠券检查任务),处理它们毫无意义,纯粹浪费资源,这导致系统负载长期居高不下,新的实时任务也无法得到及时处理,整个业务链路都被这些“僵尸消息”拖垮了,如果当初设置了合理的过期时间,比如两小时,这些过期消息就会自动被清理掉,系统恢复起来会快得多。

Redis没设过期策略,数据丢失风险其实挺大,不注意就完蛋了

(来源:知乎上一个关于数据一致性的高赞讨论)Redis没设过期时间,还会带来数据陈腐化的风险,你把数据库里的一些基础数据,像商品信息、用户配置等,缓存到Redis里,目的是加快读取速度,如果你忘了设置过期时间,或者设置了一个非常长的时间(比如一个月),那么当后台管理员在数据库里更新了这些信息后,Redis里存的还是老掉牙的旧数据,在接下来的很长一段时间里,所有读取请求拿到的都是错误、过时的信息,用户看到的是旧价格,应用读到的是旧配置,这会引起严重的线上问题,你以为你读到的缓存是“加速器”,结果却成了“绊脚石”,这种数据不一致的问题排查起来还特别麻烦,因为你很可能根本想不到是缓存数据太旧导致的,会一直怀疑是代码逻辑或数据库出了问题。

Redis没设过期策略,数据丢失风险其实挺大,不注意就完蛋了

(来源:某电商平台架构师在一次技术大会上的案例分享)除了业务层面的风险,对运维来说这也是个噩梦,Redis实例的内存使用率会变成一个只涨不降的“死海”,你根本无法通过观察内存曲线来判断业务的真实负载情况,因为内存里混杂了大量无效的、陈旧的、永不过期的数据,它们占据了空间,却对业务毫无贡献,这会导致你无法准确地进行容量规划,可能真实活跃数据只有10个G,但实例内存却用了50个G,其中40个G都是垃圾,当你需要做数据迁移、实例升级或者故障恢复时,你需要备份和移动的数据量会变得异常庞大,耗时剧增,故障恢复时间(RTO)指标根本没法看,在内存价格不菲的云服务上,你相当于一直在为垃圾数据支付昂贵的租金。

(来源:一篇深入分析Redis内存管理的技术文章)有人可能会说,Redis不是有LRU(最近最少使用)这类内存淘汰策略吗?就算没设过期时间,内存满了它自己也会清理啊,这话理论上没错,但太被动了,而且不可控,LRU策略是在内存不足的“危急时刻”才触发的,属于紧急刹车,它本身会给CPU带来额外开销,可能影响正常请求的性能,LRU算法的本意是淘汰“最近最少使用”的键,但在实践中,尤其是在数据访问模式复杂的情况下,它未必能精准地淘汰掉你最想淘汰的无效数据,很可能误伤活跃数据,把数据生命周期的管理责任完全交给一个被动的、不可预测的淘汰机制,是一种非常不负责任的行为,这就好比你的房间从不打扫,指望东西多到放不下时,地震一下帮你震出去一些——且不说效果如何,这个过程本身就足够惊悚了。

结论非常明确:在使用Redis时,为键设置一个合理的过期时间(TTL)绝不是可选项,而是必选项,这应该成为开发者和运维人员的一种肌肉记忆,无论是缓存数据、会话信息还是临时队列,在写入Redis的那一刻,就要立刻思考它的生命周期有多长,并给它一个恰当的“死法”,这就像是给数据贴上了一个保鲜期标签,时间一到,自动清理,从而从根本上避免内存无限增长、数据陈旧失效、资源被无效占用等一系列棘手问题,主动管理数据的生命周期,是保障Redis稳定、高效服务,避免“不知不觉就完蛋”这种灾难性后果的最简单、最有效的手段,忽略了这一点,Redis这个性能利器,随时可能变成一颗引爆系统稳定性的定时炸弹。