前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一次关于k8s kubectl top 和 contained ps 不一致的问题探究

一次关于k8s kubectl top 和 contained ps 不一致的问题探究

作者头像
运维部落
发布2021-07-09 11:39:06
3.4K1
发布2021-07-09 11:39:06
举报
文章被收录于专栏:运维部落

k8s kubectl top命令和contained内部 ps 看到的进程内存占用不一致。下午的时候,我被这个问题问倒了。具体如图

kubectltop-vmtop-vm

网上搜索了下,难得看到有认真研判问题的IT文章了。这篇帖子推荐给大家。

  • 一、问题背景
  • 二、Buffer & cache原理
  • 三、缓存测试
  • 四、生产环境内存飙升解决方案的建议

目录

时间线:

  • 在上 Kubernetes 的前半年,只是用 Kubernetes,开发没有权限,业务服务极少,忙着写新业务,风平浪静。
  • 在上 Kubernetes 的后半年,业务服务较少,偶尔会阶段性被运维唤醒,问之 “为什么你们的服务内存占用这么高,赶紧查”。此时大家还在为新业务冲刺,猜测也许是业务代码问题,但没有调整代码去尝试解决。
  • 再后面,出过几次OOM的问题,普遍增加了容器限额 Limits,出现了好几个业务服务是内存小怪兽,因此如果不限制的话,服务过度占用会导致驱逐,因此反馈语也就变成了:“为什么你们的服务内存占用这么高,老被 OOM Kill,赶紧查”。

一、问题背景

kubernetes 运行的java应用,内存占用持续在增长。思路如下:

代码语言:javascript
复制
kubectl exec -it pod -n xxx /bin/bash

执行 top 命令查看下当前 pod 正在运行的进程,发现在容器里面有一个 7 号进程 VSZ 占用 6522m

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

容器内部ps

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

top命令

小TIPS: RSSVSZ指标相关的参数含义:

  • RSS是Resident Set Size(常驻内存大小)的缩写,用于表示进程使用了多少内存(RAM中的物理内存),RSS不包含已经被换出的内存。RSS包含了它所链接的动态库并且被加载到物理内存中的内存。RSS还包含栈内存和堆内存。
  • VSZ是Virtual Memory Size(虚拟内存大小)的缩写。它包含了进程所能访问的所有内存,包含了被换出的内存,被分配但是还没有被使用的内存,以及动态库中的内存。

使用top 需注意:

  • 虚拟内存通常并不会全部分配给物理内存;
  • 共享内存 SHR 并不一定是共享,例如程序的代码段、非共享的动态链接库,也都算在 SHR 里。其中,SHR 也包括了进程间真正共享的内存。 因此,计算多个进程的内存使用时,不建议把所有进程的 SHR 直接相加得出结果。

所以只从 top 看是不准确的,/proc/pid/status会更精准显示进程内存占用:

代码语言:javascript
复制
cat /proc/7/status

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

proc实际内存显示

但事实是 kubectl top pod` 查看 pod 的内存占用 确实发现该 pod 内存占用确实高达 17 G ,推断并不是容器内进程内存泄露导致的问题,那这就奇怪了,是什么原因导致占用这么多内存呢?

二、Buffer & cache原理

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

众所周知,操作系统系统的内存设计,有二级,三级物理缓存。为加快运算速度,缓存被大量应用,常用数据会被buffercache之类占用,在 Linux 操作系统中会把这部分内存算到已使用。

对于容器来讲,也会把某容器引发的cache占用算到容器占用的内存上,要验证这个问题,我们可以启动一个容器, dd 创建一个大文件观察下内存变化。

代码语言:javascript
复制
[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 这一列会不断的增大。

代码语言:javascript
复制
[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

三、缓存测试

回归上述问题,会不会是 Java 程序在不停的往磁盘写文件,导致 cache 不断的增大呢?

代码语言:javascript
复制
kubectl logs -f pod-name -n namespace-name 

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

topinfo

我们尝试把 cache 清掉下看看内存是否会下降,通过配置 drop_caches强行清楚系统缓存。

代码语言:javascript
复制
sync; echo 3 > /proc/sys/vm/drop_caches
sync; echo 1 > /proc/sys/vm/drop_caches
sync; echo 2 > /proc/sys/vm/drop_caches  

当执行完如上命令后,该 pod 的内存瞬间变小,同时磁盘 I/O 持续飙升,印证是 cache 问题导致的。告知开发把日志级别从 debug 改成 info,内存问题得到解决。

TIPS /proc/sys是虚拟文件系统,是与kernel实体间进行通信的桥梁。通过修改/proc中的文件,来对当前kernel的行为做出调整。通过调整/proc/sys/vm/drop_caches来释放内存。其默认数值为0。

  • 1 表示仅清除页面缓存(PageCache):
  • 2 表示清除目录项和inode
  • 3 //表示清空所有缓存(pagecache、dentries 和 inodes

四、生产环境内存飙升解决方案的建议

  • 建议1

合理的规划资源,对每个 Pod 配置Limit,限制资源使用。kubernetes 提供了针对 pod 级别的资源限制功能,但默认没有 CPU 和内存的限额。这意味着系统中的任何 Pod 将能够像执行该 Pod 所在的节点一样,消耗足够多的 CPU 和内存。这容易导致node节点的资源被无限占用。k8s官方也并不推荐该方式。

建议方案:通过 limits 来限制 Pod 的内存和 CPU ,这样一来一旦内存达到使用限制,pod 会自动重启,而不会影响到其他 pod。

代码语言:javascript
复制
resources:
      requests:
        cpu: "200m"
        memory: "128Mi"
      limits:
        cpu: "500m"
        memory: "512Mi"
  • 建议2

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

堆内存分配:

  • JVM 最大分配的内存由**-Xmx** 指定,默认是物理内存的 1/4;
  • JVM 初始分配的内存由**-Xms** 指定,默认是物理内存的 1/64;
  • 默认空余堆内存小于 40% 时,JVM 就会增大堆直到-Xmx 的最大限制;空余堆内存大于 70% 时,JVM 会减少堆直到 -Xms 的最小限制; 因此,服务器的推荐设置是:-Xms、-Xmx 相等以避免在每次 GC 后调整堆的大小。对象的堆内存由称为垃圾回收器的自动内存管理系统回收。

非堆内存分配:

  • 由 XX:MaxPermSize 设置最大非堆内存的大小,默认是物理内存的 1/4;
  • JVM 使用**-XX:PermSize** 设置非堆内存初始值,默认是物理内存的 1/64;
  • -Xmn2G:设置年轻代大小为 2G;
  • -XX:SurvivorRatio,设置年轻代中 Eden 区与 Survivor 区的比值。
  • 建议3

应用本身优化,如本案例中所类似的问题要尽量避免在生产环境发生,即在生产环境开 debug 模式。即有安全风险,又会因为频繁的写日志会把 cache 打的非常高。建议将日志收集到专业的日志管理工具中,例如 ELK或SLS

  • 建议4

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

参考:https://blog.csdn.net/yucaifu1989/article/details/108084086

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-06-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 运维部落 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 目录
    • 一、问题背景
      • 二、Buffer & cache原理
        • 三、缓存测试
          • 四、生产环境内存飙升解决方案的建议
          相关产品与服务
          容器服务
          腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档