在容器化运维中,理解内存指标是排查“OOMKiller(内存溢出)”和“内存泄漏”的关键。Linux 内核对内存的管理是非常精细的,Used RSS 和 Cached Memory 分别代表了内存的不同分配与利用状态。
1. 核心定义
Used RSS (Resident Set Size - 常驻内存集)
- 定义:指进程当前实际占用的物理内存(RAM)。它包含了进程的代码段、数据段、堆栈、匿名内存映射(如变量存储)等。
- 本质:这是内存的“核心占用”。如果容器被系统 Kill 掉(OOM),通常就是因为 RSS 占用了超过
memory.limit_in_bytes 的额度。它是不包含被交换到磁盘的内存,也不包含文件缓存。
Cached Memory (Page Cache - 页面缓存)
- 定义:指内核为了提升 I/O 效率,将磁盘上的文件(如程序文件、日志文件、数据库数据)读取到内存中存储的副本。
- 本质:这是内存的“利用潜力”。它属于“已用内存”,但属于可回收内存。当系统或容器内存紧张时,内核会优先释放这一部分空间以供进程使用。
2. 主要区别
| 特性 | Used RSS | Cached Memory |
| 包含内容 |
进程私有内存(堆、栈、代码) |
文件系统缓存(缓存磁盘数据) |
| 回收难度 |
很难(进程主动释放,或被强制杀死) |
很容易(内核自动回收) |
| 性能影响 |
越低代表程序运行越困难 |
越高代表磁盘访问越快(性能越好) |
| 内存限制 |
计入 OOM 统计,决定是否会被杀掉 |
计入容器内存使用量,但在压力下会被置换 |
3. 具体例子分析:一个 Python 脚本的运行
假设你在 Docker 容器内运行一个读取大文件并进行数据处理的 Python 脚本:
场景 1:脚本启动并读取 500MB 的 CSV 文件
- 动作:内核将 CSV 文件内容加载到内存中以供脚本读取。
- 指标变化:
- Cached Memory:你会看到它瞬间增加了约 500MB。这是内核在为你做“缓存加速”,此时虽然内存总使用量上升了,但这是好事。
- Used RSS:脚本本身的代码和解析 CSV 产生的 Python 对象占用了一部分物理内存(例如 100MB)。
- 分析:此时容器的总内存使用(Working Set)是 600MB,但其中 500MB 是 Cached,随时可以被系统回收。
场景 2:脚本开始进行高密度的内存计算(内存泄漏)
- 动作:脚本代码逻辑错误,导致不断向一个 list 中插入对象且不释放。
- 指标变化:
- Used RSS:会持续增加,从 100MB 涨到 500MB,再涨到 800MB...
- Cached Memory:保持相对稳定,或者因为 RSS 挤占了内存而被迫被内核缓慢回收。
- 分析:这是典型的内存泄漏。当 RSS 持续上涨并突破
memory.limit 时,Linux 内核会认为容器内存溢出,触发 OOMKiller 杀掉进程。
4. 运维中的监控逻辑
在监控面板(如 Grafana)中,你应该如何看待这两个指标?
-
观察 Cached Memory 是为了排除误报:
如果你的容器内存报警了(比如达到了 limit 的 90%),不要慌。先看 RSS 和 Cached 的占比。如果 Cached 很大,说明内存紧张仅仅是因为内核缓存了太多文件,系统有足够的自动调节空间。
-
观察 RSS 是为了发现隐患:
- 如果 RSS 持续线性增长(不回落),这几乎 100% 是代码存在内存泄漏。
- 如果 RSS 激增(波峰),说明程序在处理某些大请求时瞬间需要大量计算内存,可能需要优化算法或增加容器内存限制。
-
理解“Working Set Memory”:
在 Kubernetes 中,监控指标通常使用 container_memory_working_set_bytes,它大致等于 RSS + Active Cache。这是判断容器是否会 OOM 的最准确指标。如果这个值触碰 Limit,那么容器大概率要“挂”了。
总结:
- RSS 是“身体的肌肉”,是程序运行的硬性需求。
- Cache 是“桌上的工具”,平时放在桌上(内存)是为了用着方便,当没地方放东西(内存告急)时,工具随时可以被收进抽屉(磁盘)。