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. kmemleak 和kasan 的区别

    kmemleak 和kasan 都是 Linux 内核中的一些工具和特性,用于帮助进行内存错误检测和修复.然而,它们之间有一些区别: 功能:kmemleak 用于检测内核中未释放的内存泄漏,它可以跟踪 ...

  2. 【首场重磅亮相】KaiwuDB 1.0 时序数据库线上发布会明日开启!邀您共同见证

    首场重磅亮相 KaiwuDB 是浪潮集团控股的数据库企业,以多模数据库为核心,面向工业物联网.数字能源.交通车联网.智慧城市.数字政务等多种场景,提供领先创新的数据服务软件. 新生代数据库,扬帆起航正 ...

  3. iOS 数据持久化方案-Realm的使用小结

    一.Realm介绍 1.1.Realm是一个跨平台移动数据库引擎,支持iOS.OS X(Objective-C和Swift)以及Android,核心数据引擎C++打造,并不是建立在SQLite之上的O ...

  4. js有效括号匹配

    // 定义一个括号映射 const bracketMap = [ { left: '[', right: ']' }, { left: '<', right: '>' }, { left: ...

  5. 22. uni-app 怎么跳转界面

    methods: { //gonavigate()为点击响应事件,可在HTML部分设置 @tap="gonavigate()" gonavigate(){ uni.navigate ...

  6. nodejs 和 npm 版本对应关系

    一.nodejs 和 npm 的版本是有适配的 首先看下官网列明的大概匹配关系: 官网链接地址:https://nodejs.org/zh-cn/about/previous-releases 可以查 ...

  7. 鲲鹏(ARM64)+麒麟(Kylin v10)离线部署 KubeSphere

    作者:社区用户-天行1st 本文将详细介绍,如何基于鲲鹏 CPU(ARM64) 和操作系统 Kylin V10 SP2/SP3,利用 KubeKey 制作 KubeSphere 和 Kubernete ...

  8. RPC框架JMH测试-chatgpt自动生成

    本文将介绍如何使用Java的JMH测试框架来测试RPC框架的性能.我们选择了Apache Dubbo作为目标RPC框架,Dubbo是一种高效的远程调用框架,它支持多种传输协议和序列化协议,并且具有很好 ...

  9. Java新特性-stream流

    Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据. Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达 ...

  10. 使用wxpython开发跨平台桌面应用,实现程序托盘图标和界面最小化及恢复处理

    在前面随笔<基于wxpython的跨平台桌面应用系统开发>介绍了一些关于wxpython开发跨平台桌面应用的总体效果,开发桌面应用,会有很多界面细节需要逐一处理,本篇随笔继续深入该主题,对 ...