Redis 客户端输出缓冲区为什么会撑爆内存?如何治理?
简化版
Redis 输出缓冲区用于暂存还没发给客户端的响应。客户端读得慢、返回结果太大、Pub/Sub 订阅者消费慢、复制链路阻塞时,缓冲区可能不断变大,最终导致内存飙升或连接被 Redis 断开。
详细版
Redis 处理命令后要把结果写回客户端。如果客户端网络慢、应用不读取、命令返回大结果,响应数据就会堆在服务端输出缓冲区。
普通客户端、Pub/Sub 客户端、Replica 客户端通常有不同的缓冲限制。治理时要从两边入手:服务端设置 client-output-buffer-limit,客户端避免大结果和慢消费,业务上拆分请求、限流订阅、隔离大批任务。
这类问题很容易被误判成“Redis 内存泄漏”。实际上很多时候是客户端消费能力跟不上。
完整版教学
一、输出缓冲区是什么
Redis 每个客户端连接都有输入和输出缓冲。输入缓冲保存客户端发来的命令,输出缓冲保存 Redis 准备返回但还没成功写到 socket 的响应。
如果客户端读取很快,输出缓冲只是短暂停留;如果客户端不读、网络拥塞或响应太大,缓冲就会堆积在 Redis 进程内存里。
Redis 执行命令 -> 生成响应 -> 输出缓冲区 -> TCP socket -> 客户端读取
这条链路任何一段慢,都会让前面的数据堆起来。
二、哪些场景容易撑大缓冲
第一类是大结果命令,例如 HGETALL 大 hash、SMEMBERS 大 set、LRANGE 0 -1 大列表。一次返回几十 MB,客户端稍慢就会积压。
第二类是 Pub/Sub。发布者持续推消息,订阅者处理慢,Redis 会为这个慢订阅连接缓存待发送消息。
第三类是复制。主库给从库发送复制流,如果网络慢或从库处理慢,复制缓冲会增长,影响主库内存。
三、缓冲区限制怎么理解
Redis 用 client-output-buffer-limit 限制不同客户端类型的输出缓冲。常见维度包括 hard limit、soft limit 和 soft seconds。
hard limit:超过立即断开
soft limit:持续超过一段时间才断开
soft seconds:持续时间阈值
例如 soft limit 64MB、soft seconds 60,表示客户端缓冲超过 64MB 并持续 60 秒,Redis 会断开它。这是保护实例,不是修复业务消费慢。
四、为什么不能只调大限制
调大限制会减少断连,但可能把问题转化成 Redis 内存暴涨。假设 100 个慢客户端,每个堆 50MB,就是 5GB 额外内存。
| 治理动作 | 解决什么 | 风险 |
|---|---|---|
| 调大限制 | 降低误断连 | 掩盖慢消费 |
| 拆分大查询 | 减少单次响应 | 代码改造 |
| 客户端限速 | 降低堆积 | 吞吐下降 |
| 隔离 Pub/Sub | 防止影响缓存主链路 | 运维复杂 |
真正的治理要找到“谁慢”和“为什么慢”,而不是只改配置。
五、如何排查这类问题
可以用 CLIENT LIST 查看客户端输出缓冲相关字段,定位哪个连接缓冲异常。再结合客户端 IP、应用名称、命令统计、网络监控判断来源。
CLIENT LIST
INFO clients
INFO memory
如果问题来自大查询,要改命令;来自慢消费者,要优化消费逻辑或限流;来自复制,要检查网络、从库性能和复制拓扑。
六、常见误区与追问
- 误区:Redis 内存涨就是数据 key 变多。 输出缓冲、复制缓冲、碎片和 COW 都可能增加内存。
- 误区:客户端输出缓冲越大越安全。 缓冲太大可能保护了慢客户端,却牺牲了 Redis 实例。
- 误区:Pub/Sub 消息很轻,不会撑内存。 慢订阅者跟不上发布速度时,消息会在连接缓冲中堆积。
- 追问:怎么发现是哪个客户端? 用
CLIENT LIST看连接来源和缓冲字段,再关联应用日志。 - 追问:大结果命令怎么治理? 改成分页、SCAN/HSCAN/SSCAN、字段读取或业务索引,不要一次返回全量。
七、加强记忆
记忆钩子:输出缓冲区像 Redis 门口的快递架,客户端不取件、快递又一直来,架子会先爆,不是仓库里的商品突然变多。
回答这题时抓住“响应发不出去就堆在 Redis 内存里”这个核心,再展开慢客户端、大结果、Pub/Sub、复制和配置限制,逻辑会很清楚。