Redis 为什么会卡住:fork、大 key、慢命令、AOF fsync 4 个阻塞源逐个排除
我不会起名字322· 后端 / 算法 / 数据库 技术栈 力扣 Hot100 Go 项目 Redis MySQL文章目录Redis 为什么会卡住fork、大 key、慢命令、AOF fsync 4 个阻塞源逐个排除一、先建观测能力3 条命令二、4 个阻塞源逐个排除2.1 fork 子进程耗时和数据量成正比2.2 大 key两个独立的伤害2.3 慢命令几条必须拉黑的 O(N) 操作2.4 AOF fsync取决于磁盘不取决于 Redis三、还有 3 类影响较小但别忽略的四、排查顺序先看哪 3 个指标五、结论分三档写六、小结Redis 为什么会卡住fork、大 key、慢命令、AOF fsync 4 个阻塞源逐个排除“Redis 是单线程的所以它很快”——这句话只说了前半段。后半段是正因为是单线程任何一条耗时 50ms 的命令都会把后面所有请求一起堵 50ms。Redis 不会变慢它只会在某几个瞬间完全停住然后在监控图上留下一根根尖刺。这篇文章不谈理论只解决一个问题当 P99 突然出现几十毫秒的尖刺怎么在 5 分钟内定位到是哪个阻塞源。先把观测能力建起来再逐个排除 4 类高频原因最后给一份排查顺序表。一、先建观测能力3 条命令排查阻塞靠猜是没用的。落这三条命令就够了。第一条慢查询日志。默认阈值是 10000 微秒10ms线上建议直接调到 5ms因为尖刺往往就是从 5~10ms 这段堆出来的# 查看当前配置127.0.0.1:6379CONFIG GET slowlog-*1)slowlog-log-slower-than# 阈值单位微秒-1 表示关闭2)100003)slowlog-max-len# 最多保留多少条默认 1284)128# 运行时调整不用重启127.0.0.1:6379CONFIG SET slowlog-log-slower-than5000127.0.0.1:6379CONFIG SET slowlog-max-len1024# 看最近 10 条慢日志127.0.0.1:6379SLOWLOG GET101)1)(integer)14# 日志 id2)(integer)1759999999# 发生时间戳3)(integer)48231# 耗时微秒 → 48.2ms4)1)HGETALL# 命令2)user:profile:8812# key5)10.0.3.51:412206)app-cache-3关键看第 4 项如果慢日志里反复出现同一个 key 前缀那就是大 key如果是一条KEYS/FLUSHALL那是慢命令。这一步就能区分掉两大类。第二条延迟监控。慢查询只能记录命令执行这一段fork、AOF fsync 这类不在命令执行路径上的耗时它抓不到——那要用LATENCY127.0.0.1:6379CONFIG SET latency-monitor-threshold50# 超过 50ms 才记录127.0.0.1:6379LATENCY LATEST1)1)fork2)(integer)17599998703)(integer)213# 最近一次 213ms4)(integer)431# 历史最大 431ms2)1)aof-fsync-always# 或 aof-write 相关事件2)(integer)17599998603)(integer)874)(integer)156LATENCY LATEST列出的事件名本身就是一份原因清单fork、aof-fsync-always、command、expire-cycle、eviction-del。第三条INFO的几个关键字段。一次抓齐省得来回切127.0.0.1:6379INFO stats;INFO persistence;INFO clients# stats 里关注# latest_fork_usec 最近一次 fork 耗时微秒# rejected_connections 因超 maxclients 被拒的连接数# persistence 里关注# aof_delayed_fsync 因硬盘压力被延迟的 fsync 次数 ⚠️ 非 0 就是问题# rdb_last_bgsave_status 上次 RDB 是否成功# clients 里关注# blocked_clients 当前阻塞的客户端数# client_recent_max_input_buffer 最大输入缓冲区二、4 个阻塞源逐个排除阻塞源典型现象观测命令耗时量级主要改法fork 子进程周期性尖刺与 RDB/AOF 重写时间吻合INFO stats看latest_fork_usec20ms/GB量级单实例控制在 10GB 内大 key单个 key 访问偶发变慢集群内存不均redis-cli --bigkeys、MEMORY USAGE随元素数线性增长拆分 UNLINK删除慢命令慢日志里能看到完整命令SLOWLOG GET几十 ms 到秒级禁用 改走 SCANAOF fsync与 AOF 落盘节奏吻合aof_delayed_fsync上涨INFO persistence取决于磁盘换盘 /no-appendfsync-on-rewrite2.1 fork 子进程耗时和数据量成正比RDB 生成和 AOF 重写都会fork一个子进程。fork本身要做两件事复制父进程的页表以及建立写时复制COW的映射。页表大小与实例内存量成正比经验值是20ms/GB——一个 32GB 的实例光 fork 就要 600ms 以上。这期间主线程是被阻塞的复制页表这个动作在父进程里同步完成所以监控上会看到一根明显的尖刺而且周期性与save配置或 AOF 重写触发点严丝合缝。# 确认是不是 fork 造成的127.0.0.1:6379INFO stats|greplatest_fork_usec latest_fork_usec:213478# 213ms一个 10GB 左右的实例偏慢三条改法按优先级控制单实例内存RDB 场景下建议不超过 10GB超过就拆实例或改用 Cluster降低 fork 频率把save从900 秒内 1 个 key 变化改成更宽松的多档组合AOF 重写用auto-aof-rewrite-percentage调高关闭自动重写期间的 fsyncno-appendfsync-on-rewrite yes用重写期间可能丢一点数据换重写期间不抖这是权衡不是免费午餐。2.2 大 key两个独立的伤害大 key 的麻烦是双份的内存不均在 Cluster 里一个 500MB 的 key 会让它所在的节点内存明显高于其他节点槽位迁移也会因此变慢超时阻塞单线程执行HGETALL一个 100 万字段的 hash耗时是几十毫秒量级期间所有请求排队。发现大key最省事的办法是 Redis 自带的扫描工具走SCAN实现不会阻塞redis-cli-h10.0.3.51-p6379--bigkeys# 输出片段# -------- summary -------# Sampled 1284312 keys in the keyspace!# Total key length in bytes is 32014588 (avg len 24.93)## Biggest string found user:session:bulk:20261009 has 5242880 bytes# Biggest hash found cart:items:8812 has 128403 fields# Biggest zset found rank:feed:global has 902144 members逐个 key 精确测量用MEMORY USAGE127.0.0.1:6379MEMORY USAGE cart:items:8812(integer)12583168# 12MB一个 key处理上有三条硬纪律删除必须用UNLINK而不是DEL。DEL是同步释放删一个几百万元素的 zset 会直接卡住主线程UNLINK把释放动作丢给后台线程主线程只摘除引用。不要对大 key 做全量读。HGETALL→HSCANSMEMBERS→SSCANLRANGE 0 -1→ 分页LRANGE 0 99。从设计上拆。按业务维度切分cart:items:8812拆成cart:items:8812:page:{0..N}每一个控制在 1000 个字段以内或者把大 hash 的冷字段下沉到数据库。2.3 慢命令几条必须拉黑的 O(N) 操作这一类最好查——慢日志里会直接写着命令名。要拉黑的是这几条命令为什么危险替代方案KEYS pattern遍历整个 keyspaceO(N)SCAN cursor MATCH pattern COUNT 100FLUSHALL/FLUSHDB一次性清空元素越多越慢FLUSHALL ASYNCHGETALL/SMEMBERS大 key 上等同于全量读HSCAN/SSCANSORT默认 O(N log N)还会占用额外内存排序放业务层ZRANGE key 0 -1大 zset 全量返回网络也是负担分页取或ZRANGE ... LIMITDEL大 key同步释放阻塞主线程UNLINK这些命令不一定一定是坏的但都需要在知道 key 规模的前提下才敢用。生产环境的通用做法是在中间件层直接禁用KEYS和FLUSHALL# 禁用危险命令写进 redis.conf重启生效rename-command KEYSrename-command FLUSHALLrename-command FLUSHDB2.4 AOF fsync取决于磁盘不取决于 RedisAOF 的appendfsync有三档生产上一般选everysec配置行为数据安全性能always每条写命令都 fsync最强最差直接受磁盘 IOPS 限制everysec每秒 fsync 一次默认最多丢 1 秒好但有阻塞分支no交给操作系统最多丢 30 秒最好everysec听起来很安全但它有一个隐藏的阻塞路径后台线程正在 fsync 时如果主线程也要写 AOF就会等这个 fsync 完成。磁盘压力大时比如和 RDB 重写、其他 IO 密集服务抢盘这个等待会累积。判定指标只有一个aof_delayed_fsync127.0.0.1:6379INFO persistence|grep-Eaof_delayed_fsync|aof_last_write_statusaof_delayed_fsync:37# ⚠️ 只要不是 0就说明 fsync 被延迟过aof_last_write_status:okaof_delayed_fsync只要不为 0就说明已经发生过主线程等 fsync的情况。处理顺序先看磁盘是不是到瓶颈了iostat -x 1看%util再考虑开no-appendfsync-on-rewrite yes最后才是重新评估是否必须用always。三、还有 3 类影响较小但别忽略的类别观测点说明swap/proc/pid/smaps里Swap字段一旦发生内存交换性能会断崖式下降。这是唯一必须 0 容忍的指标输入缓冲区CLIENT LIST的qbuf/qbuf-free单客户端输入缓冲区上限 1GB超了会被强断大量命令堆积时会出现输出缓冲区CLIENT LIST的omem大 key 全量返回时omem会飙升挤占内存网络INFO stats的rejected_connections超maxclients后的拒绝ulimit -n默认 1024连接多的实例必须调大输入缓冲区有个容易误解的点它不受maxmemory限制。所以设置了 maxmemory 就安全了是错的——一个客户端把 1GB 的命令堆在输入缓冲区里该 OOM 还是 OOM。四、排查顺序先看哪 3 个指标盯的时间越短越好建议按这个顺序INFO stats的latest_fork_usec—— 一个数字排除掉 fork。超过 200ms 就重点看 RDB/AOF 触发时间是否与尖刺重合。SLOWLOG GET 10—— 一眼看出有没有大 key 或慢命令。有重复 key 前缀 → 大 key有KEYS/HGETALL→ 慢命令。INFO persistence的aof_delayed_fsync—— 非 0 就是 fsync 阻塞接着去查磁盘。三条都干净再往 swapsmaps和客户端缓冲区CLIENT LIST上找。五、结论分三档写现象可复现的数字每天 02:00 出现 200~400ms 尖刺latest_fork_usec峰值 431msaof_delayed_fsync稳定为 0慢日志同期无记录。已排除的解释已排除慢命令——慢日志阈值 5ms在该时段没有新增条目已排除 AOF fsync——aof_delayed_fsync为 0已排除并发压力——同时段 QPS 只有均值的 12%。尚未证实的猜测实例内存 28GB按 20ms/GB 估算 fork 约 560ms与观测值量级吻合但还需要在同一实例上分三天记录latest_fork_usec与内存量的对应关系才能定量确认也还不能排除同机其他进程抢 CPU 的影响。六、小结Redis 性能优化里卡从来不是一个模糊的感觉它一定能对应到四件事之一fork—— 看latest_fork_usec和数据量成正比20ms/GB 是基准线大 key—— 看慢日志里重复的 key 前缀删除一律用UNLINK慢命令—— 看慢日志里的命令名KEYS和FLUSHALL直接禁用AOF fsync—— 看aof_delayed_fsync不为 0 就去查磁盘。再配上latency-monitor把非命令路径的耗时也抓进来你会发现绝大多数尖刺都能在 5 分钟内归因。这套观测思路和单线程模型本身是配套的想弄清为什么单线程还能跑 10 万 QPS可以看《Redis 进阶一单线程的 Redis 为什么这么快》而想处理主从切换时读到旧数据则是《Redis 进阶二主从复制与哨兵》那条线和本文的阻塞排查互不重叠。

相关新闻

用 Web VR 引擎搭建 3D 虚拟展厅:从素材上云到多端实时渲染的完整数据链路

用 Web VR 引擎搭建 3D 虚拟展厅:从素材上云到多端实时渲染的完整数据链路

2026年用 Web VR 引擎搭建元宇宙 3D 虚拟展厅:从素材上云到多端实时渲染的完整数据链路 2026年,3D 虚拟展厅与 VR 全景线上展会已从概念演示进入可规模化交付的工程阶段。本文面向开发者,围绕 Web VR 引擎这一技术底座,拆解一条完…

2026/10/11 7:57:06 阅读更多 →
MySQL 的脏页什么时候写回:Buffer Pool、redo log 与 4 个刷脏时机

MySQL 的脏页什么时候写回:Buffer Pool、redo log 与 4 个刷脏时机

我不会起名字322 后端 / 算法 / 数据库 📘 技术栈 | 🧩 力扣 Hot100 | 🐹 Go 项目 | 🟥 Redis | 🐬 MySQL 文章目录MySQL 的脏页什么时候写回:Buffer Pool、…

2026/10/11 7:57:06 阅读更多 →
宁夏职业院校学工信息管理系统怎么选?本地需求特点要注意什么?

宁夏职业院校学工信息管理系统怎么选?本地需求特点要注意什么?

✅作者简介:合肥自友科技 📌核心产品:智慧校园平台(包括教工管理、学工管理、教务管理、考务管理、后勤管理、德育管理、资产管理、公寓管理、实习管理、就业管理、离校管理、科研平台、档案管理、学生平台等26个子平台) 。公司所有人员均有多…

2026/10/11 7:56:05 阅读更多 →

最新新闻

2026软件测试面试指南:从Linux到AI测试的全栈质量保障

2026软件测试面试指南:从Linux到AI测试的全栈质量保障

1. 2026年软件测试面试到底在面什么做了这么多年软件测试,也面试过不少候选人,我越来越觉得现在的面试早就不是背几套题就能过关的时代了。前两天跟一个刚跳槽去大厂的兄弟聊天,他说现在的软件测试面试题已经卷到“既要懂八股、又要能落地、还…

2026/10/11 8:50:40 阅读更多 →
GET请求知识详解

GET请求知识详解

一、GET 请求是什么GET 是 HTTP 协议里最基础的一种请求方法。一句话理解:从服务器「获取 / 查询」数据,不修改服务器上的数据。 就像你在浏览器地址栏输入网址敲回车,本质就是发送 GET 请求,向服务器拿网页内容。核心特点&#x…

2026/10/11 8:50:40 阅读更多 →
AgentScope Java 2.x 系列【45】 2.0.4 版本更新:支持 Responses API、个人微信......

AgentScope Java 2.x 系列【45】 2.0.4 版本更新:支持 Responses API、个人微信......

文章目录1. 更新速览1.1 ✨ 新增1.1.1 核心 / 模型1.1.2 Harness / 工具 / 存储1.2.3 Service / Channel1.2 🔄 变更1.3 🛠️ 修复1.3.1 核心 / 状态 / 并发1.3.2 模型提供商1.3.3 Harness / 沙箱 / 集成1.4 📖 文档更新2. 重要更新2.1 OpenA…

2026/10/11 8:50:40 阅读更多 →
96% 氧化铝陶瓷怎么切?脆性材料的水刀工艺与参数边界

96% 氧化铝陶瓷怎么切?脆性材料的水刀工艺与参数边界

结论先行:氧化铝陶瓷(尤其 96% 含量)硬度高、脆性大、还导电性差。硬、脆、不导电三条凑一起,传统切割方式基本都别扭:刀具磨不动,激光有热应力、容易崩裂,线切割又不导电切不了。陶瓷为什么难切…

2026/10/11 8:50:40 阅读更多 →
风光出力联合建模:Matlab中Weibull与Beta分布及Copula耦合实现

风光出力联合建模:Matlab中Weibull与Beta分布及Copula耦合实现

风电的出力随机性有多难搞,做过新能源并网仿真的人都懂:风速忽大忽小,光照一阵一阵,你要是拿个正态分布去套,风功率曲线尾巴根本对不上。圈里早就形成了一套经验——风速用两参数Weibull分布去拟合,光照辐照…

2026/10/11 8:50:40 阅读更多 →
车载空调建模与控制算法实战:从数学推导到图纸落地

车载空调建模与控制算法实战:从数学推导到图纸落地

兄弟们,聊个接地气的话题。前阵子我把一个车载空调控制器的算法模型从零到一完整落地了一版,从最初的数学推导、仿真验证,到最后的控制算法写进控制器、再到结构图纸冻结,整个流程走完,感触挺深的。这事看起来是个传统…

2026/10/11 8:49:40 阅读更多 →

日新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 5:23:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 10:38:42 阅读更多 →