如何排查 Kubernetes 的内存增长问题?

本文深入探讨了一起生产环境中Kubernetes节点上的Pod内存占用异常升高的案例,详细解析了如何排查并解决由缓存机制导致的内存问题,强调了合理资源规划、应用优化及监控的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

作者 | 阿文

责编 | 郭芮

出品 | 优快云(ID:优快云news)

某用户生产环境的 kubernetes 节点遇到的一个问题,大概问题是这样的,用户反馈他的业务所在 pod 一在吃内存,内存占用高达 17 G 并且还是持续在增长。接到用户反馈后,我秒登 VPN ,进到用户的环境开始排查问题。

当时想的思路是这样的,既然是内存问题,那先看看这个业务所在 pod 里面到底是哪个进程在吃内存吧。

kubectl exec -it pod -n xxx /bin/bash

执行 top 命令查看下当前 pod 正在运行的进程,发现在容器里面有一个 7 号进程 VSZ 占用 6522m,这里先简单说明下 top 看到的一些和内存指标相关的参数含义:

  • RSS是Resident Set Size(常驻内存大小)的缩写,用于表示进程使用了多少内存(RAM中的物理内存),RSS不包含已经被换出的内存。RSS包含了它所链接的动态库并且被加载到物理内存中的内存。RSS还包含栈内存和堆内存。

  • VSZ是Virtual Memory Size(虚拟内存大小)的缩写。它包含了进程所能访问的所有内存,包含了被换出的内存,被分配但是还没有被使用的内存,以及动态库中的内存。

但是用户反馈的是占用 17 G之多,那很显然,并不是这个进程在捣鬼,可是整个容器里面确实就只有这个进程在运行着,并且该 Java 进程还设置了分配内存的限制,最大不会超过 4g,可是内存还是一直在涨。

而且不知道大家有没有发现,容器里面执行 top 看到的信息很少,我们对比下实际操作系统的 top 命令执行结果多了很多列,例如RES、 %MEM 等等。

在使用top 查看内存需要注意:

  • 虚拟内存通常并不会全部分配给物理内存;

  • 共享内存 SHR 并不一定是共享,例如程序的代码段、非共享的动态链接库,也都算在 SHR 里。当然,SHR 也包括了进程间真正共享的内存。所以在计算多个进程的内存使用时,不要把所有进程的 SHR 直接相加得出结果。

所以只从 top 看是不准确的,于是我们直接去查这个进程的内存占用,执行:

cat /proc/7/status

查看当前 pid 的状态,其中有一个字段VmRSS 表示当前进程所使用的内存,然而我们发现用户当前进程所占用的内存才2.3G 左右。

而通过kubectl top pod 查看 pod 的内存占用 确实发现该 pod 占用 17 G ,说明并不是容器内进程内存泄露导致的问题,那这就奇怪了,是什么原因导致占用这么多内存呢?

要继续排查这个问题,我们就需要先看看容器的内存统计是如何计算的了。

众所周知,操作系统系统的内存会有一部分被buffer、cache之类占用,在 Linux 操作系统中会把这部分内存算到已使用,那么对于容器来讲,也会把某容器引发的cache占用算到容器占用的内存上,要验证这个问题,你可以启动一个容器,然后直接使用 dd 去创建一个大文件观察下内存变化。

[root@8e3715641c31 /]# dd if=/dev/zero of=my_new_file count=1024000 bs=3024
1024000+0 records in
1024000+0 records out
3096576000 bytes (3.1 GB, 2.9 GiB) copied, 28.7933 s, 108 MB/s

你会发现,系统的 buff/cache 这一列会不断的增大。

[root@8e3715641c31 /]# free -h
              total        used        free      shared  buff/cache   available
Mem:          3.7Gi       281Mi       347Mi       193Mi       3.1Gi       3.0Gi
Swap:            0B          0B          0B

这里解释一下buff和cache的区别:

我们可以执行 man free 查看解释:

DESCRIPTION
       free displays the total amount of free and used physical and swap memory in the system, as well as the buffers and caches used by the kernel. The information is gathered by parsing /proc/meminfo. The displayed columns are:

       total  Total installed memory (MemTotal and SwapTotal in /proc/meminfo)

       used   Used memory (calculated as total - free - buffers - cache)

       free   Unused memory (MemFree and SwapFree in /proc/meminfo)

       shared Memory used (mostly) by tmpfs (Shmem in /proc/meminfo)

       buffers
              Memory used by kernel buffers (Buffers in /proc/meminfo)

       cache  Memory used by the page cache and slabs (Cached and SReclaimable in /proc/meminfo)

       buff/cache
              Sum of buffers and cache

       available
              Estimation  of  how  much  memory  is  available  for  starting  new  applications, without swapping. Unlike the data provided by the cache or free fields, this field takes into account page cache and also that not all
              reclaimable memory slabs will be reclaimed due to items being in use (MemAvailable in /proc/meminfo, available on kernels 3.14, emulated on kernels 2.6.27+, otherwise the same as free)

可以看到buff和cache 的数据来源都是来自 /proc/meminfo。

  • Buffers 是内核缓冲区用到的内存,对应的是 /proc/meminfo 中的 Buffers 值。

  • Cache 是内核页缓存和 Slab 用到的内存,对应的是 /proc/meminfo 中的 Cached 与 SReclaimable 之和。

这些数值都来自 /proc/meminfo,关于 Buffers、Cached 和 SReclaimable 的含义如下所示:

  • Buffers 是对原始磁盘块的临时存储,也就是用来缓存磁盘的数据,通常不会特别大(20MB左右)。这样,内核就可以把分散的写集中起来,统-优化磁盘的写入,比如可以把多次小的写合并成单次大的写等等。

  • Cached是从磁盘读取文件的页缓存,也就是用来缓存从文件读取的数据。这样,下次访问这些文件数据时,就可以直接从内存中快速获取,而不需要再次访问缓慢的磁盘。

  • SReclaimable 是Slab的一部分。Slab 包括两部分,其中的可回收部分,用SReclaimable记录;而不可回收部分,用SUnreclaim记录。

简单的说 buff 是对磁盘的缓存,而cache是对文件的缓存。

继续回到我们上面的这个生产环境问题,会不会是 Java 程序在不停的往磁盘写文件,导致 cache 不断的增大呢?

我们执行:

kubectl logs -f pod-name -n namespace-name 

查看,发现整屏幕不断的输出 debug 日志。然后回到开头的图,我们会发现cache 占用了 20g 左右。

我们尝试把 cache 清掉下看看内存是否会下降,执行:

sync; echo 3 > /proc/sys/vm/drop_caches //表示清空所有缓存(pagecache、dentries 和 inodes)

proc/sys是一个虚拟文件系统,可以通过对它的读写操作做为与kernel实体间进行通信的一种手段。我们可以通过修改/proc中的文件,来对当前kernel的行为做出调整。通过调整/proc/sys/vm/drop_caches来释放内存。其默认数值为0。

当其值为 1时,表示仅清除页面缓存(PageCache):

sync; echo 1 > /proc/sys/vm/drop_caches      

当其值未2 时,表示清除目录项和inode:

sync; echo 2 > /proc/sys/vm/drop_caches  

当执行完这条命令后,该 pod 的内存瞬间变小,同时磁盘 I/O 持续飙升,说明正是 cache 问题导致的,于是告诉用户调整日志的级别,把 debug 改成 info,发现内存问题得到解决。

如何解决生产环境内存飙升的问题?

首先,合理的规划资源,对每个 Pod 限制其资源使用,kubernetes 提供了针对 pod 级别的资源限制功能,默认情况下,Pod 运行没有 CPU 和内存的限额。 这意味着系统中的任何 Pod 将能够像执行该 Pod 所在的节点一样,消耗足够多的 CPU 和内存。我们可以非常容易的通过 limits 来限制 Pod 的内存和 CPU ,这样一来一旦内存达到使用限制,pod 会自动重启,而不会影响到其他 pod。

resources:
      requests:
        cpu: "200m"
        memory: "128Mi"
      limits:
        cpu: "500m"
        memory: "512Mi"

再次,针对应用本身也需要加上资源使用限制,例如 Java 程序可以限制堆内存和非堆内存的使用:

堆内存分配:

  • JVM 初始分配的内存由-Xms 指定,默认是物理内存的 1/64;

  • JVM 最大分配的内存由-Xmx 指定,默认是物理内存的 1/4;

  • 默认空余堆内存小于 40% 时,JVM 就会增大堆直到-Xmx 的最大限制;空余堆内存大于 70% 时,JVM 会减少堆直到 -Xms 的最小限制;

  • 因此服务器一般设置-Xms、-Xmx 相等以避免在每次 GC 后调整堆的大小。对象的堆内存由称为垃圾回收器的自动内存管理系统回收。

非堆内存分配:

  • JVM 使用-XX:PermSize 设置非堆内存初始值,默认是物理内存的 1/64;

  • 由 XX:MaxPermSize 设置最大非堆内存的大小,默认是物理内存的 1/4;

  • -Xmn2G:设置年轻代大小为 2G;

  • -XX:SurvivorRatio,设置年轻代中 Eden 区与 Survivor 区的比值。

再次,应用本身要做好优化,例如本案例中所类似的问题要尽量在生产环境发生,即在生产环境开 debug 模式。因为频繁的写日志会把 cache 打的非常高。可以将日志收集到专业的日志管理工具中,例如 ELK。

最后,加强监控,针对应用本身的资源使用情况和系统的各项监控指标要完善,便于及时发现问题。

你点的每个“在看”,我都认真当成了喜欢

<think>好的,用户现在问的是“什么是RSS内存?”,我需要详细解释这个概念。首先,我需要确定用户可能的背景,可能是在使用Linux系统进行开发或者运维,遇到了内存相关的问题,比如在之前的讨论中提到了hv::Buffer::enablePool的内存优化,其中提到了RSS内存的降低。因此,用户可能在性能优化过程中接触到RSS,需要进一步了解其含义和作用。 接下来,我需要回忆RSS的定义。RSS全称是Resident Set Size,即常驻内存集。它是进程实际占用物理内存的大小,包括使用的堆、栈和共享库中的内存部分。但要注意,RSS并不包括已经被换出到交换区的内存,也不包括尚未被使用的内存页。 然后,我需要对比其他内存指标,比如VSZ(虚拟内存大小),以便用户清楚区别。VSZ是进程可访问的虚拟内存总量,可能比RSS大很多,因为它包括未实际使用的内存和共享库的部分。同时,还可以提到/proc文件系统中的其他指标,比如PSS(Proportional Set Size)和USS(Unique Set Size),这些在分析内存时也很重要。 用户可能想知道RSS的实际应用场景,比如如何通过工具(如top、ps、htop、smem)查看RSS,以及如何解读这些数据。需要举例说明,比如在之前的例子中启用内存池后RSS从1.1G降到800M,说明内存使用效率提升。 此外,用户可能关心RSS的限制和潜在问题。比如RSS是否包含共享内存,可能高估实际使用的物理内存,特别是在多个进程共享库的情况下。这时候可以引入PSS的概念,解释其如何更准确地计算共享内存的部分。 还要考虑用户可能的误区,比如认为RSS高就一定不好,但实际上这取决于应用的具体情况。如果进程确实需要大量内存,高RSS是正常的。但如果RSS异常增长,可能存在内存泄漏的问题,需要进一步排查。 最后,总结RSS的重要性,帮助用户理解在性能优化、内存泄漏检测和资源监控中的作用。确保解释清晰,结构合理,使用用户能理解的语言,避免过于技术化的术语,但必要时给出术语的定义和示例。</think>### **RSS 内存详解**(Resident Set Size,常驻内存集) --- #### **一、核心定义** **RSS** 是进程**实际占用物理内存**的关键指标,表示当前时刻进程在物理内存中驻留的数据总量,包括: - 代码段(text) - 数据段(堆、栈) - 共享库中**已被加载到物理内存**的部分 - 内核数据结构(如页表) > $\text{注意}$:RSS **不包含** 已换出到交换区(swap)的内存,也不统计文件系统缓存(page cache)。 --- #### **二、与其他内存指标对比** | 指标名称 | 全称 | 描述 | 典型观测工具 | |---------|------|-----|------------| | **VSZ** | Virtual Memory Size | 进程可访问的**虚拟内存总量**(含未使用的预留内存) | `top`, `ps` | | **PSS** | Proportional Set Size | 按比例计算的共享内存(更精确的物理内存统计) | `smem` | | **USS** | Unique Set Size | 进程独占的物理内存(不含共享库) | `smem` | --- #### **三、技术特征** 1. **物理内存映射** ```bash # 示例:进程内存布局 +-------------------+ | 代码段 (text) | → RSS +-------------------+ | 数据段 (heap) | → RSS +-------------------+ | 共享库已加载部分 | → RSS +-------------------+ | 未使用的预留内存 | → VSZ - RSS +-------------------+ ``` 2. **动态变化特性** - 程序申请堆内存时,RSS **可能延迟增长**(Linux采用惰性分配策略) - 内存释放后,RSS **不会立即减少**(释放的内存可能仍标记为可复用) --- #### **四、实际应用场景** 1. **性能优化分析** ```bash # 查看进程内存(示例) $ ps -eo pid,rss,comm | grep nginx 1234 10240 nginx 5678 20480 nginx # 子进程RSS总和可能超过主进程 ``` - 对比优化前后的 RSS 变化(如内存池启用后 RSS 下降 27%) 2. **内存泄漏检测** ```bash # 持续监控 RSS 增长 $ watch -n 1 'ps -p 1234 -o rss=' ``` - 若 RSS 持续增长且无合理原因 → 疑似内存泄漏 3. **容器资源限制** ```yaml # Kubernetes 内存限制配置 resources: limits: memory: "512Mi" # 实际限制的是 RSS + 部分内核内存 ``` --- #### **五、重要技术细节** 1. **共享内存影响** - 多个进程共享同一个动态库时,该库的 RSS 会被**重复统计** - 举例:10 个进程使用 `libc.so`,每个进程的 RSS 都包含该库的内存 2. **精确测量方法** ```bash # 使用 smem 工具获取 PSS(更准确) $ smem -P nginx PID User Command USS PSS RSS 1234 www-data nginx: worker 1.2M 2.1M 5.0M ``` 3. **Linux 底层实现** - 通过 `/proc/[pid]/statm` 文件获取原始数据 - 第二列为 RSS 页数(通常页大小为 4KB) ```bash $ cat /proc/1234/statm 125680 25430 ... # 25430 pages × 4KB = ~101MB RSS ``` --- #### **六、常见误区** 1. **误区**:RSS 高 = 程序有内存问题 **实际**:数据库缓存、科学计算程序等合理场景需要高 RSS 2. **误区**:RSS 包含所有物理内存使用 **现实**:不包括内核 slab 分配器管理的部分内存 3. **误区**:RSS 下降代表内存已释放 **真相**:Linux 可能将释放的内存保留在缓存中(可通过 `echo 3 > /proc/sys/vm/drop_caches` 强制回收) --- 通过理解 RSS 内存的特性,开发者可以更准确地评估程序真实内存消耗,这对性能调优、资源监控和云原生环境下的资源配置具有重要意义。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

优快云资讯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值