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. 7.flask 源码解析:session

    目录 一.flask 源码解析:session 1.1 session 简介 1.2 解析 1.2.1 请求过程 1.2.2 session 对象 1.2.3 签名算法 1.2.4 应答过程 1.3 ...

  2. .NET使用Graphql的演示

    Graphql是什么?先来一段AI给的回答: GraphQL是一种为API设计的查询语言,与REST相比,它提供了更高效.强大和灵活的方法来与数据交互.GraphQL由Facebook于2012年开发 ...

  3. KubeSphere 部署 Zookeeper 实战教程

    前言 知识点 定级:入门级 如何利用 AI 助手辅助运维工作 单节点 Zookeeper 安装部署 集群模式 Zookeeper 安装部署 开源应用选型思想 实战服务器配置(架构 1:1 复刻小规模生 ...

  4. 【2022noip多校】异或

    [题目描述] 对于一个元素介于 \([0,2^m)\) 且互不相同的长度为 \(n\) 的序列 \(a_1, a_2 ...,a_n\) ,定义它的特征序列为 \(p_0,p_1,...,p_{2^m ...

  5. 快速搭建hadoop,zk,hbase的基础集群

    1. ZK集群,Hadoop集群,Hbase集群安装 Linux121 Linux122 Linux123 Hadoop MySQL ZK HBASE 1.1 安装Vmware,安装虚拟机集群 1.1 ...

  6. burpsuit无法启动

    在安装burpsuit时,最难的并不是找带有注册机的burpsuit安装包. 而是因为一些底层的原因,无法打开 burpsuit. 提示 Your JRE appears to be version ...

  7. CSS动画(炫酷表单)

    1.整体效果 https://mmbiz.qpic.cn/sz_mmbiz_gif/EGZdlrTDJa6yORMSqiaEKgpwibBgfcTQZNV0pI3M8t8HQm5XliaicSO42e ...

  8. 使用-solidity-开发第一个-以太坊智能合约

    目录 目录 使用 solidity 开发第一个 以太坊智能合约 前言 项目源代码 最终效果 环境搭建 智能合约内容 Truffle 创建项目 Truffle 编码 Truffle 打包 Truffle ...

  9. duxapp放弃了redux,在duxapp中局部、全局状态的实现方案

    全局状态 全局状态是一个很实用的功能,例如管理用户信息,组件间状态共享等功能都需要用到全局状态,react有很多成熟的全局状态管理工具,但是很多写起来太过麻烦,duxapp提供了几种应对不同场景的全局 ...

  10. pjsip编译、说明及vs2022使用示例

    环境: window10_x64 & vs2022 pjsip版本: 2.14.1   之前整理过pjsip 2.10的编译及python使用示例: https://www.cnblogs.c ...