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. windows下配置pytorch环境

    借鉴了B站大佬的视频,自己总结安装如下. 首先安装anaconda 按照操作顺序,依次安装,按照我个人习惯,不喜欢讲文件安装在C盘,你们自己决定. 安装完毕之后. 之后打开Anaconda Promp ...

  2. 多款国产操作系统安装数据库干货文档汇总(含Oracle/MySQL/国产数据库等)

    随着国产化的逐步推进,越来越多的企业选择将数据库安装在国产操作系统上.为帮助大家了解国产操作系统上的数据库成功搭建案例与搭建方式,本文整理了墨天轮数据技术社区上用户分享的实操文档,涵盖银河麒麟.中标麒 ...

  3. 使用 reduce 统计字符串每个字母出现的次数

    // 统计字符串每个字母出现的次数 let str = 'asdfssaaasasasasaa' let obj = str.split('').reduce(function (prev, item ...

  4. Tarjan 算法

    远古算法笔记. dfs 生成树 无向图 对于一张连通的无向图,我们可以从任意一点开始 dfs,得到原图的一棵生成树(以开始 dfs 的那个点为根). 这棵生成树上的边称作树边,不在生成树上的边称作非树 ...

  5. 优雅简单玩转python3异步并发

    在python3之后,随着async/await引入,异步调用以全新而便捷的方式让人眼前一亮. 首先,尽量用async/await定义协程 这里以使用aiohttp请求网络,async函数中,不要使用 ...

  6. k8s DockerFile中使用执行linux命令,安装字体

    #字体安装 RUN apt-get update && \apt-get -y install fontconfig xfonts-utils && \mkdir -p ...

  7. kubectl常用命令(一)

    一.查看 1.查看集群状态 # 查看客户端及服务端程序版本信息 kubectl version --short=true 

  8. mysql隐蔽的索引规则导致数据全表扫描

    索引是为了加速数据的检索,但是不合理的表结构或适应不当则会起到反作用.我们在项目中就遇到过类似的问题,两个十万级别的数据表,在做连接查询的时候,查询时间达到了7000多秒还没有查出结果. 首先说明,关 ...

  9. 强化学习训练过程中的过度拟合(overfitting)

    相关: A.I. Learns to Drive From Scratch in Trackmania 本文讨论的是强化学习中的过度拟合问题,要知道强化学习中的过拟合和其他的监督.无监督学习的过拟合不 ...

  10. Mysql数据库个人整理笔记

    数据类型 tinyint/smallint/int/bigint float double char/varchar date/time/datetime/timestamp DDL 数据库 crea ...