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

Redis 内存用满了别慌,这样调配置才靠谱,性能还能稳住

(引用来源:部分观点参考了Redis官方文档以及多位资深运维工程师的实践经验分享)

Redis的内存用满了,服务器上飘红告警,这时候千万别手忙脚乱地直接重启服务,那样很可能导致数据丢失,业务中断,你得先稳住,然后按照一套清晰的思路来排查和解决,这篇文章就给你讲讲,内存爆满之后,怎么调整配置才既靠谱又能稳住性能。

第一步:先搞清楚内存被什么占用了

Redis内存满了,就像仓库堆满了东西,你得先知道堆的是啥,才能决定是扔东西还是换大仓库,打开Redis命令行,用info memory命令看看,这里要盯住几个关键数字:

  1. used_memory:这是Redis实际分配的内存总量,就是你看到的“满”的那个值。
  2. used_memory_human:这个更直观,用M或G显示用了多少内存。
  3. used_memory_peak:Redis运行以来内存使用的峰值,帮你判断这次是不是历史最高。
  4. mem_fragmentation_ratio(内存碎片率):这个数特别重要,它是used_memory_rss(操作系统角度看Redis占了多少物理内存)除以used_memory,如果这个比值远大于1(比如大于1.5),说明内存碎片很严重了,可能你频繁修改带过期时间的键,导致腾出来的空间零零散散,新的数据又放不进去,如果比值小于1,那更危险,说明部分Redis内存被操作系统交换到硬盘上了(swap),性能会急剧下降。

第二步:根据原因选择应对策略

Redis 内存用满了别慌,这样调配置才靠谱,性能还能稳住

搞清楚状况后,对策主要有两大类:一是赶紧给现有数据“瘦身”,二是启动“淘汰机制”为新数据腾地方。

主动清理和优化数据(治本之策)

  1. 扫描并清理过期键:Redis虽然会定期清理过期键,但内存压力大时可能清理不及时,可以手动执行redis-cli --bigkeys命令(生产环境慎用,可能阻塞),找出那些占用空间巨大的键,判断是否能删除,或者,检查一下Redis配置里的maxmemory-policy(这个后面会细说),确保它不是noeviction(不淘汰),否则过期键占了坑但没及时清理也会有问题。
  2. 优化数据结构:这是长期来看最有效的办法,存一些小的数字,用Hash的hset比用多个String的set省很多内存;用ziplist编码的List、Hash、Set,在元素少、体积小时非常节省内存(需要通过配置hash-max-ziplist-entries, list-max-ziplist-size等参数来控制转换阈值),但要注意,ziplist编码在数据量大时操作性能会下降,需要权衡。

配置合理的淘汰策略(应急保底)

Redis 内存用满了别慌,这样调配置才靠谱,性能还能稳住

当内存达到上限(maxmemory参数设置的值)时,Redis的行为就由maxmemory-policy这个核心参数决定了,调对这个,是关键中的关键,它有几种策略,直接决定了是保性能还是保数据:

  • volatile-lru这是最常用、最推荐的策略之一,它只从那些设置了过期时间的键中,挑最近最少使用的(LRU算法)进行淘汰,这样既能保证大多数核心数据(没设过期时间的)安全,又能腾出空间,适合业务中有明显冷热数据区分的情况。
  • allkeys-lru:从所有键中淘汰最近最少使用的,如果你的业务数据没有严格区分核心和非核心,或者不确定,用这个更省心,能保证内存不过载。
  • volatile-ttl:从设置了过期时间的键中,挑剩余寿命最短的(TTL最小的)淘汰,这个策略比较“智能”,优先淘汰快过期的,但可能不如LRU能准确反映数据热度。
  • volatile-random / allkeys-random:随机淘汰,这属于“听天由命”型,简单粗暴,可能误伤重要数据,一般不推荐。
  • noeviction默认策略,也是最危险的策略,它不淘汰任何数据,当内存满时,所有写请求都会报错,只读请求能正常处理,除非你百分百确定数据不能丢,并且有外部容灾机制,否则在生产环境不要用这个。

怎么选? 大部分情况下,从volatile-lruallkeys-lru中选一个,如果你能给重要数据设置永不过期,那就用allkeys-lru,如果业务数据必须分冷热,热数据永不过期,冷数据设过期时间,那就用volatile-lru

第三步:调整配置和后续优化

  1. 设置合理的maxmemory:别把机器的内存全部分给Redis,通常留出10%-20%给操作系统和其他进程,比如8G内存的机器,maxmemory设为6G或6.5G比较安全。
  2. 处理高内存碎片:如果碎片率一直很高,可以尝试重启Redis(前提是有持久化或从节点能恢复数据),Redis 4.0及以上版本支持了MEMORY PURGE命令(依赖Jemalloc分配器),可以在业务低峰期手动清理碎片,但可能引起短暂延迟。
  3. 考虑横向扩展:如果单机内存实在不够用,数据量持续增长,就要考虑Redis集群(Cluster)方案了,把数据分片到多个实例上,这是解决根本问题的终极方案,但架构复杂度会提高。

内存满了别慌,顺序是:先info memory查病因 -> 然后根据业务特点,紧急情况下首要任务是立即修改maxmemory-policy为一个合理的LRU策略,避免服务不可用 -> 之后再慢慢做数据清理、结构优化、乃至架构升级,调配置不是一劳永逸的,要结合业务的增长和访问模式不断观察和调整,稳住心态,一步步来,就能既保住数据又稳住性能。