回答重点
遇到线上问题,第一时间是止损,如果发现 Redis 内存溢出,则应该立即扩容,增加 Redis 实例的内存,保证线上业务正常运行。
然后再排查内存溢出的可能原因:
- 数据过多: Redis 中存储的数据量过大,超过了可用内存。
- 数据过期策略失效: 大量的 key 没有设置过期时间,导致内存不断增长。
- 大对象或大数据结构: 某些 key 关联的数据结构(如 hash、list、set)过于庞大,占用了大量内存。
- 持久化机制影响:RDB 采用写时复制,极端情况下会占用正常两倍的内存
常见优化方案:
- 调整内存淘汰策略:根据业务需求选择合适的淘汰策略,如 allkeys-lru 或 volatile-lru,以便在内存接近上限时能够自动删除较少使用的 key。
- 设置数据过期时间: 对重要的数据设置合理的过期时间,避免无用数据长期占用内存。
- 优化数据结构: 检查大对象或大数据结构的使用情况,优化存储方案,如将大型 hash 拆分成多个小 hash。
- 垂直扩展: 升级单台 Redis 配置。
- 水平扩展: 将数据分片到多个 Redis 实例,使用集群或分布式缓存来减轻单实例的内存压力。
- 数据持久化调整: 优化持久化策略,减少额外的内存消耗,例如在低峰期触发 RDB 备份数据。
扩展知识
监控告警
针对线上的一些中间件,不论是Redis、MySQL、 MQ等,都需要计对实例对应机器的基础信息(CPU/内存/IO)和业务信息(key数量、表大小、消息堆积量等)进行些控,超过一定國值后告警,使得我们可以提前发现问题、解决问题,避免事故的产生。
例如云厂商(本地则需要自己搭建)就配套提供了很多告警接入(钉钉、企微、邮件等等),在对应中间件配置内即可
如果提前监控 Redis 的内存情况,例如占用 80% 就告警通知,那么就可以避免 Redis 内存满报错的问题
问题排查思路
观测一段时间 Redis 的内存使用量,如果发现从某一天开始,内存使用量开始明显增加,再结合那股时间的发版情况,复查那个版本提交的代码中涉及 Redis 操作,即可快速定位到问题
如果是代码 bug 则修复代码。
如果是正常业务功能增加导致需要缓存的数据变多,则思考是否可以精简存储 value,并考虑是否可以设置过期时间,或过期时间是否可以再短一些。
最终优化后,如果确定目前的应用就是占用这么多内存,则只能扩容。