容器实战高手课
李程远
eBay 总监级工程师,云平台架构师
24647 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 31 讲
容器实战高手课
15
15
1.0x
00:00/00:00
登录|注册

08 | 容器内存:我的容器为什么被杀了?

memory.usage_in_bytes
memory.oom_control
memory.limit_in_bytes
解决进程BUG
提高内存限制
控制组层级结构
参数
作用
oom_badness()函数
overcommit内存申请策略
内存不足时杀死进程
意义
OOM Killer
容器内存限制超出
处理思路
内核日志排查
Memory Cgroup
OOM Killer
原因
思考题
解决问题
容器被杀
容器内存问题

该思维导图由 AI 生成,仅供参考

你好,我是程远。
从这一讲内容开始,我们进入容器内存这个模块。在使用容器的时候,一定会伴随着 Memory Cgroup。而 Memory Cgroup 给 Linux 原本就复杂的内存管理带来了新的变化,下面我们就一起来学习这一块内容。
今天这一讲,我们来解决容器在系统中消失的问题。
不知道你在使用容器时,有没有过这样的经历?一个容器在系统中运行一段时间后,突然消失了,看看自己程序的 log 文件,也没发现什么错误,不像是自己程序 Crash,但是容器就是消失了。
那么这是怎么回事呢?接下来我们就一起来“破案”。

问题再现

容器在系统中被杀掉,其实只有一种情况,那就是容器中的进程使用了太多的内存。具体来说,就是容器里所有进程使用的内存量,超过了容器所在 Memory Cgroup 里的内存限制。这时 Linux 系统就会主动杀死容器中的一个进程,往往这会导致整个容器的退出。
我们可以做个简单的容器,模拟一下这种容器被杀死的场景。做容器的 Dockerfile 和代码,你可以从这里获得。
接下来,我们用下面的这个脚本来启动容器,我们先把这个容器的 Cgroup 内存上限设置为 512MB(536870912 bytes)。
#!/bin/bash
docker stop mem_alloc;docker rm mem_alloc
docker run -d --name mem_alloc registry/mem_alloc:v1
sleep 2
CONTAINER_ID=$(sudo docker ps --format "{{.ID}}\t{{.Names}}" | grep -i mem_alloc | awk '{print $1}')
echo $CONTAINER_ID
CGROUP_CONTAINER_PATH=$(find /sys/fs/cgroup/memory/ -name "*$CONTAINER_ID*")
echo $CGROUP_CONTAINER_PATH
echo 536870912 > $CGROUP_CONTAINER_PATH/memory.limit_in_bytes
cat $CGROUP_CONTAINER_PATH/memory.limit_in_bytes
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文介绍了容器内存管理中的重要问题:当容器中的进程使用了过多的内存时,Linux系统会主动杀死一个进程来释放内存,导致整个容器退出。文章通过模拟容器被杀死的场景,解释了OOM Killer的概念和工作原理。OOM Killer是Linux系统中的一个机制,当内存不足时,会选择杀死正在运行的进程来释放内存。文章还介绍了Linux进程的内存申请策略和OOM Killer选择进程的标准。通过这些内容,读者可以了解容器内存管理中的重要概念和机制,以及OOM Killer的工作原理,有助于他们更好地理解和解决容器内存管理中的问题。 文章还详细介绍了Memory Cgroup的运行机制,包括memory.limit_in_bytes、memory.oom_control和memory.usage_in_bytes等参数的作用。通过这些参数,读者可以了解如何限制一组进程的内存使用量,并且了解OOM Killer的触发条件和处理方式。此外,文章还提供了解决OOM问题的方法,包括如何通过内核日志及时发现OOM事件,并对消耗最多内存的进程进行分析和处理。 总的来说,本文通过深入讲解OOM Killer和Memory Cgroup的概念,帮助读者理解了容器内存管理中的关键问题,并提供了解决OOM问题的思路和方法。这对于从事容器管理和系统运维工作的读者来说,是一篇具有实际应用意义的技术文章。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《容器实战高手课》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(29)

  • 最新
  • 精选
  • Bill Du
    老师请教下 k8s中limit 是 改的 limit in bytes。那k8s request是改的mem cg中哪个指呀?

    作者回复: k8s request不修改Memory Cgroup里的参数。只是在kube scheduler里调度的时候看做个计算,看节点上是否还有内存给这个新的container。

    2020-12-03
    3
    25
  • 谢哈哈
    如果将memory oom control的参数设置为1,那么容器里的进程在使用内存到达memory limit in bytes之后,不会被oom killer杀死,但memalloc进程会被暂停申请内存,状态会变成因等待资源申请而变成task interruptable

    作者回复: @谢哈好, > 但memalloc进程会被暂停申请内存,状态会变成因等待资源申请而变成task interruptable 挺好的,能分析最后进程的状态。

    2020-12-02
    3
    22
  • 垂死挣扎的咸鱼
    请问老师:这边提到的cgroup底下的memory.usage_in_bytes是不是可以理解为通过top看到的usage与buffer/cached内存之和(这边指在容器中执行top且该容器有绑定lxcfs或者直接是kata容器即理解为top看的就是该容器的),因为我们这边用prometheus采集监控指标的时候发现container_memory_usage_bytes这个指标与cgroup中memory.usage_in_bytes是对应的而container_memory_usage_bytes这个指标实际是算上buffer/cached的内存,同时这边衍生出一个问题假如oom的评判标准是包含buffer/cached的内存使用,那是不是意味着我们在做容器内存监控的时候是应该把这个值也展示在监控中?

    作者回复: >这边提到的cgroup底下的memory.usage_in_bytes是不是可以理解为通过top看到的usage与buffer/cached内存之和 是的 > 同时这边衍生出一个问题假如oom的评判标准是包含buffer/cached的内存使用 OOM是不包含buf/cache的。总的memory usage如果超过memory limit, 那么应该是先发生memory reclaim去释放cache。

    2021-01-23
    2
    10
  • Adam
    CPU应该是可压缩资源,即便达到设置的资源限额也不会退出,而内存属于不可压缩资源,资源不足时就会发生OOM了。

    作者回复: 嗯,可以这么理解

    2020-12-04
    9
  • wuqilv
    老师,我在ubuntu上按照文章进行操作,容器没有按照预期那样发生 oom kill,查看 state ,"OOMKilled": false。

    作者回复: @wuqilv, 你可以用free看一下,是不是swap打开了?

    2020-12-02
    6
    5
  • 垂死挣扎的咸鱼
    老师这边请教一个问题,今天排查oom的日志时发现 agent invoked oom-killer: gfp_mask=0x6000c0(GFP_KERNEL), nodemask=(null), order=0, oom_score_adj=-998 ...... Killed process 3267 (agent) total-vm:4912320kB, anon-rss: 2074576kB, file-rss: 23000kB, shmem-rss:0kB 这么一段,其中对容器limit限制是2GIB,因此猜测为oom触发条件是 anon-rss + file-rss > limit时触发,然后看到您在评论里有描述过条件是: 新申请的内存+ memory.usage_in_bytes - reclaim memory > memory.limit_in_bytes 所以这边对这个新申请内存有些疑惑,这边有两种猜测: (1)这边的新申请内存指的是虚拟内存吗,如果是的话是不是意味着oomkill流程触发是在程序申请内存的时候,但是这边看之前oom日志中vm的内存已经远超limit了 (2) 这边猜测这边的新申请内存是实际的物理内存这样,按照这种猜测oomkill流程是在程序实际使用时触发该流程,如果这种猜测是准的话,想请问一下是否anon-rss + file-rss 就等于新申请的内存+ memory.usage_in_bytes - reclaim memory 这样 这边确实对oom这一块十分困惑,网上找到的资料也千奇百怪,内核代码不知道该怎么入手看这一块,所以想请教一下老师这些问题,麻烦老师了

    作者回复: @垂死挣扎的咸鱼 > (1) 新申请的内存还是指物理内存。虚拟内存是不会引起OOM的。 > 想请问一下是否anon-rss + file-rss 就等于新申请的内存+ memory.usage_in_bytes - reclaim memory 其实这里最大的一点就是内核的内存是否被计入到cgroup memory中。缺省情况内核使用的内存会被计入到cgroup里, 不过对于大部分运行应用程序的容器里, anon-rss + file-rss就是最主要的物理内存开销(这里不包含内核内存)。 但是如果一个容器中的进程对应的内核内存使用量很大那么我觉得更加准确的就是看 “新申请的内存+ memory.usage_in_bytes - reclaim memory” 了。

    2021-02-25
    2
    3
  • Lemon
    老师,请问控制组之间是什么关系呢? 按照本章的树状的层级结构图所示,group1 分出 group2 和 group3 。 此时 group1 里的 memory.limit_in_bytes 设置的值是 200MB,这里的 200MB 是代表是的什么呢? 是指 group2 + group3 + group1 的所有进程使用的内存总值就不能超过 200MB? 还是单纯的指 group2 与 group3 中各自的所有进程使用的内存总值就不能超过 200MB?

    作者回复: 是第一种情况: > 是指 group2 + group3 + group1 的所有进程使用的内存总值就不能超过 200MB?

    2021-01-29
    3
  • 维c
    参照着网络上的解析和内核的代码看了一下整个oom回收的flow,发现oom_killer_disabled这个标志位在out_of_memory 函数的一开始就做了检测,那么这个标志位由什么决定的呢?如果容器内的进程也可以设置这个标志位,是不是就等于禁止掉了回收机制而导致容器内进程内存管理的失控呢?

    作者回复: 在memory cgroup中可以通过memory.oom_control来禁止对应cgroup中的oom killer。 禁止oom killer不会导致内存管理失控,它也不是内存的回收机制。

    2020-12-23
    2
  • Geek_ba556d
    k8s的memory的request,limit限制对应cgroup的参数是什么?

    作者回复: limit 对应 Memory Cgroup中的memory.limit_in_bytes k8s request不修改Memory Cgroup里的参数。只是在kube scheduler里调度的时候看做个计算,看节点上是否还有内存给这个新的container。

    2020-12-03
    2
    2
  • Acter
    请问老师:进程的cache和buffer也会计入进程已使用的物理内存页面数吗?

    作者回复: @Acter,好问题,下一课,我会讲这个问题

    2020-12-02
    2
收起评论
显示
设置
留言
29
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部