Linux里的容器被OOM killed的两种情况

生产上遇到过几次容器实例被OOM的现象,总结一下LInux OOM的两种触发条件。我的虚拟机是ubuntu 24.0.4版本,分配4G内存,在我的虚拟机上复现这两种case。

一 宿主机物理内存不够

当linux上所有应用程序的内存需求加起来超出了物理内存(包括 swap)的容量,内核(OOM killer)必须杀掉一些进程才能腾出空间保障系统正常运行。oom_score分数最高的进程在这个时候会被杀掉。

用来每隔一秒分配100MB RSS物理内存的程序

#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>#define BLOCK_SIZE (100*1024*1024)int main(int argc, char **argv)
{int thr, i;char *p1;for (i = 0; ; i++) {p1 = malloc(BLOCK_SIZE);memset(p1, 0x00, BLOCK_SIZE);printf("set to %d Mbytes\n", i * 100);sleep(1);}return 0;
}

Dockerfile

FROM ubuntu:24.04COPY ./mem-alloc/mem_alloc /CMD ["/mem_alloc", "2000"]

Makefile

all: imagemem_alloc: mem-alloc/mem_alloc.cgcc -o mem-alloc/mem_alloc mem-alloc/mem_alloc.c
image: mem_allocdocker build -t registry/mem_alloc:v1 .
clean:rm mem-alloc/mem_alloc -fdocker stop mem_alloc;docker rm mem_alloc;docker rmi registry/mem_alloc:v1

执行sudo make后,启动容器,不指定内存上限,故意让这个docker吃掉所有的宿主机的内存

sudo docker run --privileged -it  registry/mem_alloc:v1 /bin/bash

容器内执行

root@4c81480d3366:/# echo 1 > /sys/fs/cgroup/memory.oom.group 
root@96bd973a3a59:/# ./mem_alloc 1000
set to 0 Mbytes
set to 100 Mbytes
set to 200 Mbytes
set to 300 Mbytes
set to 400 Mbytes
set to 500 Mbytes

观察docker stats 的输出,容器消耗完所有虚拟机的内存后,被杀死
请添加图片描述
执行dmesg

[86949.786621] oom-kill:constraint=CONSTRAINT_NONE,nodemask=(null),cpuset=docker-96bd973a3a598d2fe5dfda4213cbb2ea028b0a4c3922fb50830daa12a9a4ecba.scope,mems_allowed=0,global_oom,task_memcg=/system.slice/docker-96bd973a3a598d2fe5dfda4213cbb2ea028b0a4c3922fb50830daa12a9a4ecba.scope,task=mem_alloc,pid=13545,uid=0
[86949.786647] Out of memory: Killed process 13545 (mem_alloc) total-vm:6556108kB, anon-rss:3656448kB, file-rss:128kB, shmem-rss:0kB, UID:0 pgtables:12968kB oom_score_adj:0
[86949.788874] Tasks in /system.slice/docker-96bd973a3a598d2fe5dfda4213cbb2ea028b0a4c3922fb50830daa12a9a4ecba.scope are going to be killed due to memory.oom.group set
[86949.788889] Out of memory: Killed process 13518 (bash) total-vm:4296kB, anon-rss:0kB, file-rss:0kB, shmem-rss:0kB, UID:0 pgtables:60kB oom_score_adj:0
[86949.789235] Out of memory: Killed process 13545 (mem_alloc) total-vm:6556108kB, anon-rss:3656448kB, file-rss:128kB, shmem-rss:0kB, UID:0 pgtables:12968kB oom_score_adj:0
[86951.427580] docker0: port 1(veth1e6a35b) entered disabled state
[86951.427667] vethce0aa4c: renamed from eth0
[86951.445966] docker0: port 1(veth1e6a35b) entered disabled state
[86951.446626] veth1e6a35b (unregistering): left allmulticast mode
[86951.446705] veth1e6a35b (unregistering): left promiscuous mode
[86951.446707] docker0: port 1(veth1e6a35b) entered disabled state

这个容器实例因为RSS使用了3.6G,宿主机的所有可用物理内存,导致被宿主机killed掉。

K8s配置最佳实践

生产环境的容器的内存的limit和request配置一样,不要超卖,一旦宿主机的物理内存不够,一定会有容器被宿主机kill掉。

二 docker里的进程使用的内存超过了cgroup的限制

容器实例使用的内存如果超过了cgroup(control group)的限制,会被内核直接杀掉

其他不变,容器启动命令增加内存限制的参数-m 2000m --memory-swap 2000m

sudo docker run  -m 2000m --memory-swap 2000m  --privileged -it  registry/mem_alloc:v1 /bin/bash

容器内执行

root@4c81480d3366:/# echo 1 > /sys/fs/cgroup/memory.oom.group 
root@96bd973a3a59:/# ./mem_alloc 1000
set to 0 Mbytes
set to 100 Mbytes
set to 200 Mbytes
set to 300 Mbytes
set to 400 Mbytes
set to 500 Mbytes

观察docker stats 的输出,容器的使用内存达到cgroup的限制后,被杀掉
请添加图片描述
使用dmesg,查看内核日志

[88880.963934] oom-kill:constraint=CONSTRAINT_MEMCG,nodemask=(null),cpuset=docker-38bdd956b75425c816afa4f5d3071bc4b175065cf405414c41a23ebf44e5f2fa.scope,mems_allowed=0,oom_memcg=/system.slice/docker-38bdd956b75425c816afa4f5d3071bc4b175065cf405414c41a23ebf44e5f2fa.scope,task_memcg=/system.slice/docker-38bdd956b75425c816afa4f5d3071bc4b175065cf405414c41a23ebf44e5f2fa.scope,task=mem_alloc,pid=13890,uid=0
[88880.963948] Memory cgroup out of memory: Killed process 13890 (mem_alloc) total-vm:2050332kB, anon-rss:2042752kB, file-rss:128kB, shmem-rss:0kB, UID:0 pgtables:4116kB oom_score_adj:0
[88880.967339] Tasks in /system.slice/docker-38bdd956b75425c816afa4f5d3071bc4b175065cf405414c41a23ebf44e5f2fa.scope are going to be killed due to memory.oom.group set
[88880.967351] Memory cgroup out of memory: Killed process 13859 (bash) total-vm:4296kB, anon-rss:384kB, file-rss:0kB, shmem-rss:0kB, UID:0 pgtables:48kB oom_score_adj:0
[88880.968337] Memory cgroup out of memory: Killed process 13890 (mem_alloc) total-vm:2050332kB, anon-rss:2042752kB, file-rss:128kB, shmem-rss:0kB, UID:0 pgtables:4116kB oom_score_adj:0
[88881.076584] docker0: port 1(veth0cb68cb) entered disabled state
[88881.076763] veth6ef9720: renamed from eth0
[88881.094585] docker0: port 1(veth0cb68cb) entered disabled state
[88881.096610] veth0cb68cb (unregistering): left allmulticast mode
[88881.096714] veth0cb68cb (unregistering): left promiscuous mode
[88881.096717] docker0: port 1(veth0cb68cb) entered disabled state

内核日志的关键词和上面的不一样,Memory cgroup out of memory, 有关键词cgroup

jvm参数配置最佳实践

jvm进程要控制好堆的大小,堆配置的过大,容易导致jvm整体内存超过了容器的限制值,进而被OS kill掉。堆的大小自适应容器的内存大小,建议配置65% 到 75%之间,MaxRAMPercentage和MinRAMPercentage建议配置一样,避免申请或释放内存消耗机器性能。(下面的几个参数在Java 8u191 +之后才支持, 不生效的话注意版本)

-XX:+UseContainerSupport 
-XX:InitialRAMPercentage=70.0  
-XX:MaxRAMPercentage=70.0 
-XX:MinRAMPercentage=70.0 

memory.oom.group 参数说明

/sys/fs/cgroup/memory.oom.group

A read-write single value file which exists on non-root cgroups. The default value is “0”.

Determines whether the cgroup should be treated as an indivisible workload by the OOM killer. If set, all tasks belonging to the cgroup or to its descendants (if the memory cgroup is not a leaf cgroup) are killed together or not at all. This can be used to avoid partial kills to guarantee workload integrity.

如果这个参数设置成1,那么当内存超过cgroup的限制,整个cgroup组里所有进程会被视为一个整体一起杀掉。如果设置成0,当内存不够用的时候,会杀掉cgroup分组里oom_score分数最高的那个进程。
为了实现容器整体被kill掉,上面的两个例子里,/sys/fs/cgroup/memory.oom.group 文件内容都需要手动改成1

参考资料


  1. https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/69260.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用Express.js和SQLite3构建简单TODO应用的后端API

使用Express.js和SQLite3构建简单TODO应用的后端API 引言环境准备代码解析1. 导入必要的模块2. 创建Express应用实例3. 设置数据库连接4. 初始化数据库表5. 配置中间件6. 定义数据接口7. 定义路由7.1 获取所有TODO项7.2 创建TODO项7.3 更新TODO项7.4 删除TODO项 8. 启动服务器 …

Windows本地部署DeepSeek-R1大模型并使用web界面远程交互

文章目录 前言1. 安装Ollama2. 安装DeepSeek-r1模型3. 安装图形化界面3.1 Windows系统安装Docker3.2 Docker部署Open WebUI3.3 添加Deepseek模型 4. 安装内网穿透工具5. 配置固定公网地址 前言 最近爆火的国产AI大模型Deepseek详细大家都不陌生&#xff0c;不过除了在手机上安…

低代码开发与传统开发:未来的技术路线选择

在科技飞速发展的当下&#xff0c;软件开发技术日新月异&#xff0c;低代码开发与传统开发作为两种重要的开发模式&#xff0c;正站在未来技术路线选择的十字路口&#xff0c;引发了众多企业和开发者的关注。它们各自有着独特的优势和适用场景&#xff0c;究竟该如何抉择&#…

二、0-1搭建springboot+vue3前后端分离-登录页面

项目仓库地址&#xff1a;zgw-admin: 从0-1搭建一个springbootvue3的项目&#xff0c;这是源码 本次主要是为了&#xff1a; a.写登录页面 b.element plus组件是否能正常使用 c.页面调用ts是否正常&#xff0c;无参和有参的函数 首页的图片&#xff1a; 页面效果 1、引入…

《翻转组件库之发布》

背景 继《翻转组件库之打包》_杨晓风-linda的博客-CSDN博客之后&#xff0c;组件库已经可以正常构建&#xff0c;那如何像elementUI等组件库那样&#xff0c;用npm安装&#xff0c;按照既定的用法使用即可呢&#xff1f;本篇便为你揭晓 资料相关 1、npm官方文档&#xff1a;…

Spring Task之Cron表达式

&#x1f31f; Spring Task高能预警&#xff1a;你以为的Cron表达式可能都是错的&#xff01;【附实战避坑指南】 开篇暴击&#xff1a;为什么你的定时任务总在凌晨3点翻车&#xff1f; “明明设置了0 0 2 * * ?&#xff0c;为什么任务每天凌晨3点执行&#xff1f;” —— 来…

web-JSON Web Token-CTFHub

前言 在众多的CTF平台当中&#xff0c;作者认为CTFHub对于初学者来说&#xff0c;是入门平台的不二之选。CTFHub通过自己独特的技能树模块&#xff0c;可以帮助初学者来快速入门。具体请看官方介绍&#xff1a;CTFHub。 作者更新了CTFHub系列&#xff0c;希望小伙伴们多多支持…

如何在 Kafka 中实现自定义分区器

今天我来给大家分享一下如何在 Kafka 中实现一个自定义分区器。Kafka 是一个分布式流处理平台&#xff0c;能够高效地处理海量数据。默认情况下&#xff0c;Kafka 使用键的哈希值来决定消息应该发送到哪个分区&#xff0c;但是有时我们需要根据特定的业务逻辑来定制分区策略。这…

【FPGA】 MIPS 12条整数指令【2】

目录 实现slt 仿真 代码 完整代码 ID.v DataMem.v define.v EX.v IF.v InstMem.v MEM.v MIPS.v RegFile.v Soc.v soc_tb.v 实现slt 仿真 ori r1,r0,1100h ori r2,r0,0020h ori r3,r0,ff00h ori r4,r0,ffffh addi r5,r0,ffff slt r6,r5,r4 slt r6,r4,r…

MySQL 进阶专题:索引(索引原理/操作/优缺点/B+树)

在数据库的秋招面试中&#xff0c;索引&#xff08;Index&#xff09;是一个经典且高频的题目。索引的作用类似于书中的目录&#x1f4d6;&#xff0c;它能够显著加快数据库查询的速度。本文将深入探讨索引的概念、作用、优缺点以及背后的数据结构&#xff0c;帮助你从原理到应…

nginx目录结构和配置文件

nginx目录结构 [rootlocalhost ~]# tree /usr/local/nginx /usr/local/nginx ├── client_body_temp # POST 大文件暂存目录 ├── conf # Nginx所有配置文件的目录 │ ├── fastcgi.conf # fastcgi相关参…

vue-router 有哪几种导航钩子?

在 Vue Router 中,导航钩子(Navigation Guards)用于控制路由的进入和离开,可以在路由变化的不同阶段执行逻辑。Vue Router 提供了多种类型的导航钩子,主要包括以下几种: 一、全局导航钩子 全局导航钩子在路由实例上定义,适用于所有路由的导航。 beforeEach在每次路由切…

信息学奥赛一本通 2101:【23CSPJ普及组】旅游巴士(bus) | 洛谷 P9751 [CSP-J 2023] 旅游巴士

【题目链接】 ybt 2101&#xff1a;【23CSPJ普及组】旅游巴士(bus) 洛谷 P9751 [CSP-J 2023] 旅游巴士 【题目考点】 1. 图论&#xff1a;求最短路Dijkstra, SPFA 2. 动态规划 3. 二分答案 4. 图论&#xff1a;广搜BFS 【解题思路】 解法1&#xff1a;Dijkstra堆优化 …

C基础寒假练习(6)

一、终端输入行数&#xff0c;打印倒金字塔 #include <stdio.h> int main() {int rows;printf("请输入倒金字塔的行数: ");scanf("%d", &rows);for (int i rows; i > 0; i--) {// 打印空格for (int j 0; j < rows - i; j) {printf(&qu…

vim modeline

1. 什么是 Vim 模型行&#xff08;modeline&#xff09;&#xff1f; Vim 模型行是嵌入在文件中的特殊注释行&#xff0c;用于告诉 Vim 编辑器如何配置编辑选项。它的语法格式如下&#xff1a; # vim: 选项1值1:选项2值2:...它以 # vim: 开头&#xff08;# 是注释符&#xff…

【C# 】图像资源的使用

在C#中&#xff0c;图像资源的使用方式方法主要依赖于你所使用的框架和库。以下是几种常见的使用图像资源的方法&#xff1a; Windows Forms 直接加载图像&#xff1a; 使用System.Drawing.Image.FromFile()方法可以直接从文件系统加载图像。 Image image Image.FromFile(&qu…

OpenGL学习笔记(六):Transformations 变换(变换矩阵、坐标系统、GLM库应用)

文章目录 向量变换使用GLM变换&#xff08;缩放、旋转、位移&#xff09;将变换矩阵传递给着色器坐标系统与MVP矩阵三维变换绘制3D立方体 & 深度测试&#xff08;Z-buffer&#xff09;练习1——更多立方体 现在我们已经知道了如何创建一个物体、着色、加入纹理。但它们都还…

java后端开发面试常问

面试常问问题 1 spring相关 &#xff08;1&#xff09;Transactional失效的场景 <1> Transactional注解默认只会回滚运行时异常&#xff08;RuntimeException&#xff09;&#xff0c;如果方法中抛出了其他异常&#xff0c;则事务不会回滚&#xff08;数据库数据仍然插…

使用conda创建自己的python虚拟环境,与其他python版本独立区分

使用 Conda 创建和使用自己的运行环境非常简单&#xff0c;以下是详细步骤&#xff1a; 1. 安装 Anaconda 或 Miniconda 如果你尚未安装 Anaconda 或 Miniconda&#xff0c;可以访问 Anaconda 官网 或 Miniconda 官网 下载并安装。 2. 创建新的 Conda 虚拟环境 创建虚拟环境…

OSPF基础(1):工作过程、状态机、更新

OSPF基础 1、技术背景&#xff08;与RIP密不可分&#xff0c;因为RIP中存在的问题&#xff09; RIP中存在最大跳数为15的限制&#xff0c;不能适应大规模组网周期性发送全部路由信息&#xff0c;占用大量的带宽资源以路由收敛速度慢以跳数作为度量值存在路由环路可能性每隔30秒…