Redis:内存陡增100%深度复盘

简介: 事故因大KEY调用量随流量增长,导致带宽占满,Redis内存使用率迅速达100%。虽有淘汰机制,但缓冲区激增(尤其Pub/Sub输出缓冲)占用大量内存,超出实例容量,致使SET/GET超时崩溃。根本原因为客户端缓冲区失控,非数据本身膨胀,最终Redis无法服务。

简单回顾

事故回溯总结一句话:

(1)因为大KEY调用量,随着白天自然流量趋势增长而增长,最终在业务高峰最高点期占满带宽使用100%。

(2)从而引发redis的内存使用率,在5min之内从0%->100%。

(3)最终全面GET SET timeout崩溃(11点22分02秒)。

(4)最终导致页面返回timeout。

未解之谜

疑问点:内存使用率100% 就等同于redis不可用吗?

解答:正常使用情况下,不是。

redis有【缓存淘汰机制】,Redis 在内存使用率达到 100% 时不会直接崩溃。相反,它依赖内存淘汰策略来释放内存,确保系统的稳定性。

学习更多:24 替换策略:缓存满了怎么办?

https://time.geekbang.org/column/article/294640

这个配置在哪里?

大部分同学都是不会主动去调整这里的参数的。

因此大概率默认的是:volatile-lru

  • 行为: 使用 LRU(Least Recently Used,最近最少使用)算法驱逐键。volatile-lru 仅驱逐设有过期时间的键,allkeys-lru 则驱逐所有键。
  • 适用场景: 缓存场景,不介意丢失一些数据。

确保你根据实际需求配置适当的内存淘汰策略,以便在内存达到上限时,系统能够稳定地处理新请求,而不会出现写操作失败的情况(只要不是noeviction)。

也就是说,照理SET GET都应该没啥问题才对(先不考虑其他复杂命令)。

  • 尽管 Redis 本身不会轻易崩溃,但如果内存耗尽且没有淘汰策略或者淘汰策略未能生效,Redis 可能拒绝新的写操作,并返回错误:OOM command not allowed when used memory > 'maxmemory'
  • 如果系统的配置或者操作系统的内存管理不当,可能会导致 Redis 进程被操作系统杀死。

疑问点:但是事故现象就是:内存使用率100% 时,redis不可用,怎么解释?

猜测1:会是淘汰不及时导致的性能瓶颈吗?

也就是说:写入的速度>>淘汰的速度。

解答:如果是正常的业务写入,不可能!
  • redis纯内存,淘汰速度是非常快的;
  • 这个业务特性,也并非高频写入;

这个redis实例其实里面存储的KEY很少,最终占了整个实例的内存使用率<5%。

不太符合正常使用下KEY不断增多,最终挤爆内存使用率的问题。

因此,初步结论:Redis 的崩溃一般不会是由于单纯写入速度超过淘汰速度引起的,尤其是使用了合理的内存淘汰策略时;如果写入速度非常高,而淘汰策略无法及时清除旧数据,Redis 可能会非常频繁地进行键的查找和淘汰操作,从而导致性能下降。

18 波动的响应延迟:如何应对变慢的Redis?(上)

https://time.geekbang.org/column/article/286549

具体机制如下:

过期 key 的自动删除机制。它是 Redis 用来回收内存空间的常用机制,应用广泛,本身就会引起 Redis 操作阻塞,导致性能变慢,所以,你必须要知道该机制对性能的影响。

Redis 键值对的 key 可以设置过期时间。默认情况下,Redis 每 100 毫秒会删除一些过期 key,具体的算法如下:

1.采样:

ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP 个数的 key,并将其中过期的 key 全部删除;

2.如果超过 25% 的 key 过期了,则重复删除的过程,直到过期 key 的比例降至 25% 以下。

ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP 是 Redis 的一个参数,默认是 20,那么,一秒内基本有 200 个过期 key 会被删除。这一策略对清除过期 key、释放内存空间很有帮助。如果每秒钟删除 200 个过期 key,并不会对 Redis 造成太大影响。

但是,如果触发了上面这个算法的第二条,Redis 就会一直删除以释放内存空间。注意,删除操作是阻塞的(Redis 4.0 后可以用异步线程机制来减少阻塞影响)。所以,一旦该条件触发,Redis 的线程就会一直执行删除,这样一来,就没办法正常服务其他的键值操作了,就会进一步引起其他键值操作的延迟增加,Redis 就会变慢。

那么,算法的第二条是怎么被触发的呢?其中一个重要来源,就是频繁使用带有相同时间参数的 EXPIREAT 命令设置过期 key,这就会导致,在同一秒内有大量的 key 同时过期。

可以类比JVM频繁GC造成的性能影响。

猜测2:那就是写入太凶猛,且是【非正常业务写入】

那到底是什么导致了内存使用率激增呢??

蛛丝马迹

如何解决Redis内存使用率突然升高:

https://help.aliyun.com/zh/redis/support/how-to-solve-the-sudden-increase-in-redis-memory-usage?spm=a2c4g.11186623.0.i12

因此查阅了资料,发现最为贴近的答案。

证据支撑

真相大白

果然是这样,说明内存是被【缓冲区】挤爆的。

21 缓冲区:一个可能引发“惨案”的地方:

https://time.geekbang.org/column/article/291277

知识点:Redis的内存占用组成

使用info memory进行分析(我随便模拟了一个缓冲区溢出的case,并非事故现场,因为当时不会)。

# Memory
used_memory:1072693248
used_memory_human:1023.99M
used_memory_rss:1090519040
used_memory_rss_human:1.02G
used_memory_peak:1072693248
used_memory_peak_human:1023.99M
used_memory_peak_perc:100.00%
used_memory_overhead:1048576000
used_memory_startup:1024000
used_memory_dataset:23929848
used_memory_dataset_perc:2.23%
allocator_allocated:1072693248
allocator_active:1090519040
allocator_resident:1090519040
total_system_memory:16777216000
total_system_memory_human:16.00G
used_memory_lua:37888
used_memory_lua_human:37.89K
used_memory_scripts:1024000
used_memory_scripts_human:1.00M
maxmemory:1073741824
maxmemory_human:1.00G
maxmemory_policy:noeviction
allocator_frag_ratio:1.02
allocator_frag_bytes:17825792
allocator_rss_ratio:1.00
allocator_rss_bytes:0
rss_overhead_ratio:1.00
rss_overhead_bytes:0
mem_fragmentation_ratio:1.02
mem_fragmentation_bytes:17825792
mem_not_counted_for_evict:0
mem_replication_backlog:0
mem_clients_slaves:0
mem_clients_normal:1048576000
mem_aof_buffer:0
mem_allocator:jemalloc-5.1.0
active_defrag_running:0l
azyfree_pending_objects:0

分析和解释

从上面的 INFO memory 输出中,我们可以看到一些关键信息,这些信息表明大部分内存被缓冲区占用殆尽:

1.内存使用情况:

  • used_memory: 1072693248 (1.02 GB)
  • maxmemory: 1073741824 (1.00 GB)

上面的输出表明,当前内存使用几乎达到了配置的最大内存限制,内存已接近耗尽。

2.缓冲区占用:

  • used_memory_overhead: 1048576000 (1.00 GB)

这个值表示 Redis 开销的内存,包括缓冲区、连接和其他元数据。在这种情况下,大部分 used_memory (1.02 GB) 被 used_memory_overhead (1.00 GB) 占用,这意味着大部分内存都被缓冲区等开销占据。

3.数据集占用:

  • used_memory_dataset: 23929848 (23.93 MB)
  • used_memory_dataset_perc: 2.23%

这里显示,实际存储的数据只占了非常少的一部分内存(约 23.93 MB),而绝大部分内存被缓冲区占据。

4.客户端缓冲区:

  • mem_clients_normal: 1048576000 (1.00 GB)

这表明普通客户端连接占用了约 1.00 GB 内存,这通常意味着输出缓冲区可能已经接近或达到了设定的限制。

5.内存碎片:

  • allocator_frag_ratio: 1.02
  • mem_fragmentation_ratio: 1.02

碎片率不高,表明内存被合理使用但被缓冲区占用过多。

总结

从上面的例子可以看出,Redis 的内存几乎被缓冲区占用殆尽。以下是具体的结论:

  • 当前内存使用 (used_memory) 已经接近最大内存限制 (maxmemory),即 1.02 GB 接近 1.00 GB 的限制。
  • 内存开销 (used_memory_overhead) 很大,主要被客户端普通连接使用(可能是输出缓冲区),而实际的数据仅占用了很少的内存。
  • 分配器和 RSS 碎片率 (allocator_frag_ratio 和 mem_fragmentation_ratio) 较低,表明碎片不是问题。
缓冲内存的理论最大值推导
为什么要有缓冲区

Redis工作原理-单客户端视角简单版:

Redis工作原理-单客户端视角复杂版:

缓冲区的功能其实很简单,主要就是用一块内存空间来暂时存放命令数据,以免出现因为数据和命令的处理速度慢于发送速度而导致的数据丢失和性能问题。

因此,Redis工作原理-多客户端视角简单版(含缓冲区)。

输入缓冲区

定义

内存占用

输出缓冲区

定义

内存占用

Redis Server 的输出大小通常是不可控制的。存在bigkey的时候,就会产生体积庞大的返回数据。另外也有可能因为执行了太多命令,导致产生返回数据的速率超过了往客户端发送的速率,导致服务器堆积大量消息,从而导致输出缓冲区越来越大,占用过多内存,甚至导致系统崩溃。Redis 通过设置 client-output-buffer-limit来保护系统安全。

不出意外,默认是:32MB 8MB 60s

对于 Pub/Sub 连接:

  • 硬限制:每个 Pub/Sub 客户端连接的输出缓冲区最大可以达到 32MB 。
  • 连接池最大连接数:300 个连接,其中所有连接假设都在处理 Pub/Sub 消息且达到了最大缓冲区限制。

故理论上,最大输出缓冲区可以达到:

最大输出缓冲区占用=硬限制×连接池最大连接数最大输出缓冲区占用=硬限制×连接池最大连接数=32MB×300=9600MB=9.375GB

因此,在这种配置下,所有 Pub/Sub 连接的输出缓冲区理论上的最大占用内存为 9.375 GB。

因此,在client-output-buffer-limit是默认的情况下,最大占用内存为 9.375 GB。

所以,MAX(输出缓冲区+输入缓冲区)是否会造成内存使用率100%?

当然!

MAX(输出缓冲区+输入缓冲区)=10.375GB >> 一个实例的内存规格(在本case中,是2G)

最后的效果就是:

对象存储的部分因为是有过期时间的,过期了自然被清理了。

  • 【缓冲内存】↑ (涌入)
  • 【对象内存】↓ (定时清理)
  • 并受MAX内存掣肘(上限)

最终的结局:Redis 的内存完全被缓冲区占据。

自然,每当有SET请求进来的时候,SET不进来——因为「内存淘汰策略」(maxmemory-policy) 淘汰的是【对象内存】,压根起不到作用!!!

结论:

Redis 的内存完全被缓冲区占据,实际上 Redis 将无法正常工作,包括数据存储(SET 操作)和数据读取(GET 操作)。

分析:为何缓冲区激增(Redis不可用的时间点11:22:02,之前都发生了什么)

知道了缓冲区挤爆Redis内存会导致Redis不工作之后,接下来就是分析为何当时出现了缓冲区激增并最终导致redis不可用。

实例信息

相关代码

案件还原
相关文章
|
机器学习/深度学习 人工智能 自然语言处理
揭秘Google Gemini:AI界的多模态革命者与ChatGPT-4的较量
揭秘Google Gemini:AI界的多模态革命者与ChatGPT-4的较量
1200 0
|
2月前
|
数据采集 人工智能 数据挖掘
一个人如何完成一个部门的工作?AI智能体工作流搭建教程
本文详解如何用AI智能体搭建“一人部门”工作流:将运营、客服、销售等岗位工作拆解为五层流程(目标→输入→处理→审核→输出→复盘),结合知识库、4类核心智能体、低代码编排工具与人工审核机制,实现可复用、可迭代的自动化协作。零基础也能3天跑通。
|
4月前
|
人工智能 Linux API
OpenClaw部署图文指南|阿里云无影云电脑+本地MacOS/Linux/Windows11+千问/Coding Plan API配置教程
本文完整覆盖2026年阿里云轻量服务器部署及本地MacOS/Linux/Windows11部署OpenClaw(Clawdbot)步骤流程及阿里云千问大模型API配置或市场上免费大模型Coding Plan API配置及常见问题解答,从阿里云无影云电脑一键部署,到本地三大操作系统全流程搭建,再到阿里云千问与免费Coding Plan大模型API对接,全程提供可直接复制的代码命令、可视化操作指引与高频问题解决方案,确保零基础用户一次部署成功、稳定运行。
494 5
|
8月前
|
机器学习/深度学习 人工智能 自然语言处理
择业地图:想成为AI产品经理,该考CAIE还是微软AI-900?
当“AI+”成为全行业转型的核心命题,AI产品经理作为连接技术与业务的关键角色,已成为职场热门赛道。面对招聘要求中“具备AI相关技能认证优先”的隐性门槛,CAIE(注册人工智能工程师)与微软AI-900(Azure AI基础认证)成为多数求职者的备选清单。但两者并非“二选一”的竞争关系,而是适配不同职业路径的能力锚点。要做出理性选择,需先厘清:AI产品经理真正需要的认证价值是什么?两种认证的核心差异又在哪里?
|
人工智能 自然语言处理 API
推荐几个常用免费的文本转语音工具
本文推荐了几款免费的文本转语音工具,包括功能全面的AI易视频、支持多语言的Google TTS、操作便捷的Natural Reader、离线使用的Balabolka以及轻量级的Speech2Go。其中AI易视频特别适合小说转语音,可智能分配角色音色,打造广播剧般的听觉体验。这些工具各具特色,能满足不同场景需求,助力内容创作更高效。
4307 5
|
10月前
|
Web App开发 人工智能 自然语言处理
2025年SEO工具合集!60 个免费付费的都找齐了
2025年最新整理全网免费与付费SEO工具清单,涵盖关键词研究、页面优化、技术SEO、本地搜索、外链建设及内容创作等全方位工具,助力网站提升排名与流量。
|
存储 人工智能 监控
星云智控科技-优雅草星云物联网AI智控系统软件产品技术栈一览表-优雅草卓伊凡
星云智控科技-优雅草星云物联网AI智控系统软件产品技术栈一览表-优雅草卓伊凡
454 7
星云智控科技-优雅草星云物联网AI智控系统软件产品技术栈一览表-优雅草卓伊凡
|
SQL 存储 Linux
从配置源到数据库初始化一步步教你在CentOS 7.9上安装SQL Server 2019
【11月更文挑战第7天】本文介绍了在 CentOS 7.9 上安装 SQL Server 2019 的详细步骤,包括系统要求检查与准备、配置安装源、安装 SQL Server 2019、配置 SQL Server 以及数据库初始化(可选)。通过这些步骤,你可以成功安装并初步配置 SQL Server 2019,进行简单的数据库操作。
766 1
|
机器学习/深度学习 人工智能 自然语言处理
AI驱动的自动化测试:提升软件质量的未来之路
【9月更文挑战第3天】AI驱动的自动化测试是提升软件质量的未来之路。它借助AI技术的力量,实现了测试用例的智能生成、测试策略的优化、故障预测与定位等功能的自动化和智能化。随着技术的不断进步和应用场景的不断拓展,AI驱动的自动化测试将在未来发挥更加重要的作用,为软件开发和运维提供更加高效、准确和可靠的解决方案。