深色模式
内存容量评估
内存不够的后果比 CPU 不够严重得多:直接 OOM Kill,没有"慢一点"的过渡。评估内存要看峰值、看增长、还要区分"缓存占用"和"真实占用"。
适用环境
- 已部署 node_exporter,能查
node_memory_* - 应用为常驻进程(Java/Go/Node 等)
- 知道容器或实例的 memory limit
bash
# 查看当前内存与 limit(cgroup v2)
cat /sys/fs/cgroup/memory.max
cat /sys/fs/cgroup/memory.current1
2
3
2
3
操作步骤
1. 计算真实使用率
bash
# available 才是"还能用多少",free 命令的第一行会让人误判
free -m1
2
2
promql
# 可用率
node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes1
2
2
promql
# 已用率(排除缓存,缓存是可回收的)
1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)1
2
2
2. 取峰值而不是当前值
promql
# 近 7 天内存使用率峰值
max_over_time(
(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)[7d:5m]
)1
2
3
4
2
3
4
promql
# 进程 RSS 峰值
max_over_time(process_resident_memory_bytes{process="order-api"}[7d:1m])1
2
2
3. 分离缓存与真实占用
Java 应用尤其要注意:堆内存 + 元空间 + 堆外(DirectBuffer、线程栈)+ 页缓存。
bash
# 看 JVM 各区占用
jcmd "$(pgrep -f order-api | head -1)" VM.native_memory summary | head -201
2
2
promql
# JVM 堆使用 / 堆上限
jvm_memory_bytes_used{area="heap"} / jvm_memory_bytes_max{area="heap"}1
2
2
4. 判断是否存在内存泄漏(增长趋势)
promql
# 对比 3 天前与现在的 RSS,持续增长且不回落即为泄漏嫌疑
process_resident_memory_bytes{process="order-api"}
- process_resident_memory_bytes{process="order-api"} offset 3d1
2
3
2
3
bash
# 短期验证:连续采样 RSS
for i in $(seq 1 6); do
pgrep -f order-api | head -1 | xargs -I{} awk '/VmRSS/{print $2}' /proc/{}/status
sleep 600
done1
2
3
4
5
2
3
4
5
5. 计算需求容量
text
需求内存 = 峰值 RSS × (1 + 增长预留) ÷ 目标水位
示例:
峰值 RSS = 5.2 GB
未来 6 个月增长 = 30%
目标水位 = 70%
需求 = 5.2 × 1.3 ÷ 0.7 ≈ 9.7 GB → 选 16 GB 规格 或 12 GB 并密切观察1
2
3
4
5
6
7
2
3
4
5
6
7
6. 检查 OOM 历史
bash
# 内核 OOM 记录
sudo dmesg -T | grep -i -E 'oom|killed process'
sudo journalctl -k | grep -i 'out of memory'
# 容器被 kill 的记录
docker inspect --format '{{.State.OOMKilled}}' <container>
kubectl get pod <pod> -o jsonpath='{.status.containerStatuses[0].lastState.terminated.reason}'1
2
3
4
5
6
7
2
3
4
5
6
7
验证
promql
# 容量结论验证:峰值使用率落在 60%~75% 区间为健康
max_over_time(
(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)[7d:5m]
)1
2
3
4
2
3
4
同时确认:近 7 天无 OOM 事件、RSS 曲线平稳无单向增长、SWAP 使用接近 0。
bash
# SWAP 被使用说明内存真的不够了
free -m | grep -i swap1
2
2
常见坑
拿 free 的 used 当真实占用
Linux 会把空闲内存拿去做 page cache,free 第一行 used 接近总内存是常态。必须看 available,否则会误判为内存不足而过度扩容。
容器 limit 等于宿主机内存
在容器里看 /proc/meminfo 得到的是宿主机值,进程会以为自己有很多内存而直接被 cgroup OOM Kill。要用 cgroup 文件判断。
只按堆内存配容器
Java 容器 OOM 多数死在堆外:线程栈、DirectBuffer、JNI、glibc arena。经验做法是容器 limit 至少比 -Xmx 大 30%~50%。
忽略每实例内存随连接数增长
每建一个连接都会分配读写缓冲。并发从 1000 涨到 10000 时内存可能翻倍。压测时必须按目标并发数测内存。