1.问题描述:

经常有业务反馈在使用容器云平台过程中监控展示的业务使用内存不准,分析了下kubernetes采集Pod内存使用的实现原理以及相应的解决思路

2.问题分析:

2.1 问题排查:

监控数据是采集的kubernetes上报的container_memory_working_set_bytes字段:

分析kubernetes代码可以看到container_memory_working_set_bytes是取自cgroup memory.usage_in_bytes 与memory.stat total_inactive_file两者的差值:

分析内核代码发现memory.usage_in_bytes的统计数据是包含了所有的file cache的, total_active_file和total_inactive_file都属于file cache的一部分,并且这两个数据并不是业务真正占用的内存,只是系统为了提高业务的访问IO的效率,将读写过的文件缓存在内存中,file cache并不会随着进程退出而释放,只会当容器销毁或者系统内存不足时才会由系统自动回收。

__add_to_page_cache_locked..->mem_cgroup_cache_charge->mem_cgroup_charge_common->__mem_cgroup_try_charge->mem_cgroup_do_charge

综上分析,kubernetes采用memory.usage_in_bytes - total_inactive_file并不能真正计算出Pod实际已使用的内存空间,当Pod内存资源紧张时total_active_file也是可回收利用的。

2.2 验证分析结论:

通过下面例子可以验证上面的分析:

<1> 创建一个容器:

cgcreate -g memory:test-docker-memory

docker run --cgroup-parent=/test-docker-memory --net=none -v /root/test_mem:/test -idt --name test --privileged csighub.tencentyun.com/admin/tlinux2.2-bridge-tcloud-underlay:latest

<2> 进入容器遍历一个大小约为580M message的文件:

memory.stat统计数据total_inactive_file增加580多M:

<3> 对同一个文件再遍历一遍

此时total_inactive_file的统计数据会将message文件占用的内存转为total_active_file

<3> 通过drop_caches触发一次内存回收可以看到active(file) 和 inactive(file)都会被回收:

3 解决方法:

3.1 Linux 如何计算free内存

要解决该问题先要了解内核是如何统计free内存的,从下面代码可以知道内核计算空闲内存方法如下(容器平台未使用swap):

NR_FREE_PAGES + NR_FILE_PAGES – NR_SHMEM_PAGES + NR_SLAB_RECLAIMABLE

从下列代码可以知道NR_FILE_PAGES在无swap的情况下包含cache pages和buffer pages:

因此有效内存可以通过转化为cgroup memory.meminfo对应字段计算得出:

available = MemFree+Cached- Shmem + Buffers+ SReclaimable)

3.2 Cgroup的真实使用内存如何计算?

由于cgroup当前并未提供memory.meminfo的统计信息,所以kubernetes无法通过

该公式获取Pod所在的cgroup已使用内存。

Cgroup当前提供了memory.stat和memory.usage_in_bytes的统计信息,看下如何将memory.meminfo的计算方法转为memory.stat的计算公式:

因为”Shmem”(即IPCS shared memory & tmpfs)包含在Cached中,而不在Active(file)和Inactive(file)中,并且Active(file)和Inactive(file)还包含Buffers。另外mem lock的内存不在LRU链表中,所以如果有mlock的话,得出如下等式(mlock包括file和anon两部分,/proc/meminfo中并未分开统计,下面的mlock_file只是用来表意,实际并没有这个统计值):

【Active(file) + Inactive(file) + Shmem + mlock_file】== 【Cached + Buffers】

memory.usage_in_bytes统计包含了Cached和Buffers,Cached中除了mlock_file和Shmem(IPCS shared memory & tmpfs)外,其他部分File cache是可以回收使用的,Buffers也是可以回收利用的,所以pod容器所在cgroup实际使用的内存计算公式可以转化为(因memory.stat未导出SReclaimable,这里忽略SReclaimable):

real_used = memory.usage_in_bytes – (Cached- Shmem - mlock_file + Buffers )

= memory.usage_in_bytes – memory.stat .( total_inactive_file + total_active_file )

因此kubernetes container_memory_working_set_bytes字段在计算实际已使用内存时应该改为

memory.usage_in_bytes – memory.stat .( total_inactive_file + total_active_file )

附录:

Cache包含ipcs shm和tmpfs内存验证:

1.运行申请tmpfs和ipcs shm共享内存前读取当前memory.stat数据:

2. 拷贝一个580M左右的文件到tmpfs挂载点/run占用580M的共享内存,运行IPCS 测试程序申请一段300M的ipcs shm:

Tmpfs + ipcs shm = 582349583+314572800 = 896922383

3.再次查看memory.stat的total_cache,增加的值约等于步骤2中tmpfs和ipcs shm增加的内存使用值:

Added total_cache = 1077981184 – 181751808 = 896229376

ipcs shm测试代码:

# cat test_shm.c

#include <sys/types.h>

#include<stdio.h>

#include<string.h>

#include <errno.h>

#include <sys/ipc.h>

#include <sys/shm.h>

#include <sys/sem.h>

#include <time.h>

#define LEN (300*1024*1024)

static char buf[LEN] = {0};

int main(int agrc, char *argv[])

{

key_t key = 888999;

int shmid = shmget(key, LEN, IPC_CREAT | IPC_EXCL);

if(shmid == -1)

{

printf("shmget err: %d %s\n", errno, strerror(errno));

return -1;

}

void *p = shmat(shmid, NULL, SHM_R | SHM_W);

if (p == NULL)

{

printf("shmat failed\n");

return -1;

}

//shmctl(shmid, IPC_RMID, 0);

printf("first shmid: %d p: %p\n", shmid, p);

memset(p, 'a', LEN-1);

p = shmat(shmid, NULL, SHM_R | SHM_W);

if (p == NULL)

{

printf("shmat xx failed\n");

return -1;

}

memcpy(buf, p, LEN-1);

printf("second shmid: %d p: %p\n", shmid, p);

getchar();

shmctl(shmid, IPC_RMID, 0);

}

kubernetes上报Pod已用内存不准问题分析的更多相关文章

  1. Kubernetes之POD

    什么是Pod Pod是可以创建和管理Kubernetes计算的最小可部署单元.一个Pod代表着集群中运行的一个进程. Pod就像是豌豆荚一样,它由一个或者多个容器组成(例如Docker容器),它们共享 ...

  2. Kubernetes之Pod使用

    一.什么是Podkubernetes中的一切都可以理解为是一种资源对象,pod,rc,service,都可以理解是 一种资源对象.pod的组成示意图如下,由一个叫”pause“的根容器,加上一个或多个 ...

  3. Kubernetes中 Pod 是怎样被驱逐的?

    前言 在 Kubernetes 中,Pod 使用的资源最重要的是 CPU.内存和磁盘 IO,这些资源可以被分为可压缩资源(CPU)和不可压缩资源(内存,磁盘 IO).可压缩资源不可能导致 Pod 被驱 ...

  4. Kubernetes K8S之CPU和内存资源限制详解

    Kubernetes K8S之CPU和内存资源限制详解 Pod资源限制 备注:CPU单位换算:100m CPU,100 milliCPU 和 0.1 CPU 都相同:精度不能超过 1m.1000m C ...

  5. Kubernetes:Pod基础知识总结

    Blog:博客园 个人 官方文档详尽介绍了Pod的概念. 概念 Pods are the smallest deployable units of computing that you can cre ...

  6. Kubernetes核心技术Pod

    Kubernetes核心技术Pod Pod概述 Pod是K8S系统中可以创建和管理的最小单元,是资源对象模型中由用户创建或部署的最小资源对象模型,也是在K8S上运行容器化应用的资源对象,其它的资源对象 ...

  7. kubernetes之pod生命周期,pod重启策略, 镜像拉取策略

    pod声明周期(状态):pending , running, succeeded, failed, unknown 挂起(Pending):Pod 已被 Kubernetes 系统接受,但有一个或者多 ...

  8. Kubernetes基石-pod容器

    引用三个问题来叙述Kubernetes的pod容器 1.为什么不直接在一个Docker容器中运行所有的应用进程. 2.为什么pod这种容器中要同时运行多个Docker容器(可以只有一个) 3.为什么k ...

  9. Kubernetes服务pod的健康检测liveness和readiness详解

    Kubernetes服务pod的健康检测liveness和readiness详解 接下来给大家讲解下在K8S上,我们如果对我们的业务服务进行健康检测. Health Check.restartPoli ...

  10. Kubernetes的Pod进阶(十一)

    一.Lifecycle 官网:https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/ 通过前面的分享,关于pod是什么相信看 ...

随机推荐

  1. SegmentFault 基于 Kubernetes 的容器化与持续交付实践

    本文是根据 KubeSphere 云原生 Meetup 杭州站讲师祁宁分享内容整理而成. SegmentFault 是一家综合性技术社区,由于它的内容跟编程技术紧密相关,因此访问量的波动也和这一群体的 ...

  2. Top100题(上)

    Top100(上) 散列 1. 两数之和 struct MyListNode { int val; int pos; struct MyListNode *next; }; // 散列表 typede ...

  3. Web渗透08_文件上传

    1 文件上传漏洞概述 文件上传几乎是每一个web,或者说是任何 服务器客户端模式 应用的必备功能,用户在自己的文章,博文中要上相关图片.用户上传自己的头像.网盘用户上传各种文件.等等.若服务器对此没有 ...

  4. 鸿蒙NEXT应用上架与分发步骤详解

    大家好,我是 V 哥.今天的文章来聊一聊HarmonyOS NEXT应用上架.当你开发.调试完HarmonyOS应用/元服务,就可以前往AppGallery Connect申请上架,华为审核通过后,用 ...

  5. SVN上的修改提交时间、作者以及简单的SVN操作说明

    情况说明 因为部分SVN记录上传时间不符合规范,需要修改因此有这个需求.默认情况下SVN是不允许修改时间和作者信息,需要服务器进行配置. 一.服务的配置变更 我用的是Windows版本,在这个地方配置 ...

  6. 92. 反转链表 II Golang实现

    题目描述: 给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right .请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 ...

  7. Next.js 从零入门到实战 3:2024最新完整教程 | 包含SSR、API路由和性能优化

    CSS样式学习 上一篇文章讲到如何创建一个脚手架程序,目前我们已经有了一个nextjs的基本框架,因此我们可以在这个基础上进行改造.打开我们项目中的page.tsx页面,这里是程序的主页面,也就是我们 ...

  8. TypeError: add_triangle_mesh(): incompatible function arguments. The following argument types are supported: 问题终于解决了!!!!

    1 2024.10.12 14:52 Traceback (most recent call last): File "terrain_creation.py", line 119 ...

  9. Solon MVC 的 @Mapping 用法说明

    在 Solon Mvc 里,@Mapping 注解一般是配合 @Controller 和 @Remoting,作请求路径映射用的.且,只支持加在 public 函数 或 类上. 1.注解属性 属性 说 ...

  10. po文件如何转为excel

    其实.po文件是一种翻译文件格式,类似于 key - value的列表 可以理解为两列,由于我们想把这个po数据读出来放入 excel.因为大部分人看不懂po文件的.虽然我们可以借助工具 poedit ...