Redis 内存占用持续上涨,info memory 看到 mem_fragmentation_ratio 飙到 2 以上,可登录到跳板机才发现根本没有 redis-cli 可用,这种场景在运维一线太常见了。与其在每台机器上安装 Redis 客户端,不如直接用官方镜像跑一个一次性的 redis-cli 容器,几秒钟就能建立连接。本文介绍如何容器化运行 redis-cli,并结合 MEMORY DOCTOR 这个内置诊断命令,快速判断 Redis 的内存健康状况。

为什么要容器化 redis-cli
最直接的理由是环境隔离。生产服务器往往有严格的变更管控,安装任何软件包都需要走审批流程,而拉取一个 Docker 镜像并不算对系统做变更。redis 官方镜像自带完整客户端工具集,包括 redis-cli、redis-benchmark、redis-check-rdb 等,一个镜像解决所有排查需求。
第二个理由是版本一致性。不同发行版仓库里的 redis-tools 版本差异很大,老版本的 redis-cli 连接新版本 Redis 时,部分新命令(比如某些 MEMORY 子命令)可能无法正确解析响应。容器化之后可以精确指定镜像 tag,让客户端版本和服务端版本保持一致,避免诊断工具本身带来的干扰。
第三点便于团队标准化。把诊断命令封装成脚本或别名,团队成员在任何装了 Docker 的机器上都能用完全相同的方式排查问题,减少“我这里没问题”这类沟通成本。
容器方式运行 redis-cli 的正确姿势
最基础的用法是 docker run 加上 it 参数进入交互式终端,把镜像的入口命令覆盖为 redis-cli,并指定目标 Redis 地址:
docker run -it --rm redis:7.2 redis-cli -h 10.0.1.20 -p 6379
--rm 保证容器退出后自动清理,不会留下垃圾容器。如果 Redis 设置了密码或启用了 ACL,再补上 -a 或 --user 参数即可。注意密码会留在 shell 历史记录里,更稳妥的做法是使用环境变量:
docker run -it --rm \ -e REDISCLI_AUTH=your_password \ redis:7.2 redis-cli -h 10.0.1.20 -p 6379
如果只是想执行单条命令拿结果就走,把命令直接跟在后面即可,适合写进自动化脚本:
docker run --rm redis:7.2 \ redis-cli -h 10.0.1.20 -p 6379 memory doctor
还有两个细节值得注意。一是网络层面:容器默认使用 bridge 网络,只要目标 Redis 对宿主机网络可达,容器内一般也能访问;但如果 Redis 绑定了 bind 127.0.0.1 且跑在宿主机上,就要给容器加 --network host 才能连上。二是 TLS 场景,云上的 Redis 通常要求加密连接,此时需要加 --tls 并挂载证书文件:
docker run --rm \ -v /etc/redis/certs:/certs:ro \ redis:7.2 redis-cli -h redis.example.internal -p 6380 \ --tls --cert /certs/client.crt \ --key /certs/client.key --cacert /certs/ca.crt memory doctor
MEMORY DOCTOR 诊断了什么
MEMORY DOCTOR 是 Redis 4.0 引入的诊断命令,它会综合分析当前实例的内存状态,用自然语言给出评估结论。它不修改任何数据,只读不写,可以放心在生产环境执行。
它的检查维度主要包括以下几个方面。第一是内存碎片率,也就是 mem_fragmentation_ratio,这个值是操作系统视角的 RSS 内存与 Redis 自身统计的已用内存之比。低于 1 说明 Redis 使用的内存超过了操作系统分配的物理内存,可能发生了 swap;在 1 到 1.5 之间属于正常范围;超过 1.5 甚至达到 2 以上,说明碎片严重或者某些客户端的输出缓冲区占用了大量内存。
第二是主从复制积压缓冲区(repl-backlog)的占用情况。第三是每个数据库的 key 数量与平均每个 key 的内存开销,如果平均开销异常高,它会提示是否存在设计不合理的大 value。此外它还会关注峰值内存(used_memory_peak)与当前内存的差距,判断是否刚刚发生过内存突增导致大量碎片。
典型输出像这样:
10.0.1.20:6379> memory doctor Sam, I detected a few issues in this Redis instance memory implants: * Peak memory: in the past this instance used more than 150% the memory that is currently using. This is the peak memory used. If this peak was caused by a transient workload, it is normal. However if this instance is using less memory than it used to, and this growth pattern was not expected, it may be the symptom of a memory fragmentation issue. * Client buffers: 72.5% of used memory is accounted for by client buffers. This may be the symptom of a poorly designed client application.
输出开头那句 Sam,是 Redis 作者留下的一个彩蛋,致敬电影《碟中谍》里的人物。真正有价值的信息在下面的条目里,每一条都对应一个具体的内存异常信号,务必逐条核对。
结合 MEMORY STATS 深入定位
MEMORY DOCTOR 给出的是概括性结论,想知道具体数字还得配合 MEMORY STATS。这个命令返回一份详细的内存分布报告,包括每个子进程的内存、复制缓冲区、各数据库的 overhead 等。常见的排查路径是:先用 DOCTOR 看有没有报警条目,再用 STATS 找出具体是哪一块占了大头。
docker run --rm redis:7.2 \ redis-cli -h 10.0.1.20 memory stats | head -50
如果碎片率确实很高,可以从两个方向处理。短期方案是在低峰期执行 activedefrag yes 开启主动碎片整理(需要 Redis 编译时带 jemalloc 支持,容器化部署的官方镜像通常都带)。长期方案是审视数据结构用法,比如把大量小 hash 合并成大 hash 以减少 key 数量,或者检查是否存在大量已删除但未释放的过期 key 触发了惰性释放堆积。
如果是 client buffers 占比过高,重点排查消费速度慢的客户端,尤其是 pub-sub 订阅者和执行慢查询阻塞期间仍持续接收数据的连接,可以用 client list 查看 omem 字段找出输出缓冲区最大的连接,再配合 client-output-buffer-limit 做限制兜底。
最后建议把容器化的诊断命令固化成 shell 别名,例如 alias rdoc='docker run --rm redis:7.2 redis-cli -h 10.0.1.20 memory doctor',遇到内存告警时一条命令出结论,把排查时间压缩到最短。容器化的意义就在于此:工具随取随用,环境永远干净,诊断动作可以标准化复用。