pod oom
OOM Killer 机制是如何工作的?
OOMKilled实际上不是 Kubernetes 原生的——它是 Linux Kernel 的一个特性,称为OOM KillerKubernetes 用来管理容器生命周期的。该OOM Killer机制监视节点内存并选择占用过多内存的进程,应将其杀死。重要的是要意识到OOM Killer即使节点上有空闲内存也可能会终止进程。
Linux 内核oom_score为主机上运行的每个进程维护一个。这个分数越高,进程被杀死的机会就越大。另一个值,称为oom_score_adj,允许用户自定义 OOM 进程并定义应终止进程的时间。
Kubernetes 在oom_score_adj为 pod 定义服务质量 (QoS) 类时使用该值。可以为 pod 分配三个 QoS 类:
保证
可爆破
最大的努力
每个 QoS 类都有一个匹配值oom_score_adj:
服务质量 OOM_SCORE_ADJ
保证 -997
最大的努力 1000
可爆破 min(max(2, 1000—(1000 * memoryRequestBytes) / machineMemoryCapacityBytes), 999)
因为“Guaranteed” pod 的值较低,所以它们是最后一个在内存不足的节点上被杀死的。“BestEffort” pod 最先被杀死。
由于内存问题而被杀死的 pod 不一定会从节点中驱逐——如果节点上的重启策略设置为“始终”,它将尝试重启 pod。
要查看 pod 的 QoS 类,请运行以下命令:
Kubectl get pod -o jsonpath=’{.status.qosClass}’
要查看oom_scorepod:
跑kubectl exec -it /bin/bash
要查看oom_score,运行cat/proc//oom_score
要查看oom_score_adj,run cat/proc//oom_score_adj
原因 解析度
已达到容器内存限制,并且应用程序的负载比正常情况高 增加 pod 规范中的内存限制
已达到容器内存限制,应用程序出现内存泄漏 调试应用程序并解决内存泄漏
节点过度使用——这意味着 pod 使用的总内存大于节点内存 调整容器中的内存请求(最小阈值)和内存限制(最大阈值)
memory.usage_in_bytes-total_inactive_
kubectl top 得到的内存使用数据原来是包含 cache 的
突然之间,我感觉到曙光就在眼前,有可能还真的是 cache 占用了内存才导致的 OOM
回想一下,正常的 cache 可以提高磁盘数据的读写数据,在读的时候,会拷贝一份文件数据放到内存中,这部分是可回收的,一旦程序内存不足了,会回收部分 cache 的空间,保证程序的正常运行
然后我也发现了 directsync 这个选项,就是不使用缓存,直接将数据写入磁盘,这正是我想要的啊。
重新改了下 cdi 的代码,编译,制作镜像,创建 pod,还真的是再也没有出现 OOM ,到现在问题全部解决了,真的爽啊~
在此之前,我潜意识里以为只有进程实际占用的内存才是 oom 的依据,没有想到缓存分为两种:读缓存和写缓存,
读缓存是可随时回收的内存空间,不会引起内存问题,但写缓存,是不能随时回收的内存空间,只有将数据存入磁盘后
,内在才能回收,这部分是有可能会引起内存问题的。
[580237.375615] memory: usage 585936kB, limit 585936kB, failcnt 75129
[580237.375616] memory+swap: usage 585936kB, limit 9007199254740988kB, failcnt 0
[580237.375618] kmem: usage 24148kB, limit 9007199254740988kB, failcnt 0
[580237.375618] Memory cgroup stats for /kubepods/burstable/pod6b212546-f5dd-4fdf-bcc7-72a686638102:
回想一下,正常的 cache 可以提高磁盘数据的读写数据,在读的时候,会拷贝一份文件数据放到内存中,这部分是可回收的,一旦程序内存不足了,会回收部分 cache 的空间,保证程序的正常运行。
可见读文件的缓存,不会影响内存的申请,更别说 OOM,但在写的时候,情况就不一样了
在写的时候,由于进程处理数据的速度,可能会远大于数据落盘的速度,所以为提高格式转化和数据导入的速度,一般会先将转化好的数据存入缓存中,存入缓存后,进程可以立马 return 回去继续下一堆数据的处理,不用傻傻地等待数据全写入磁盘。
而存在于缓存之中的数据,则由操作系统同步写入磁盘,这样一来,数据落盘就变成了一个异步的过程,大大提高了写入的速度。
大腿一拍,这不就有可能会出问题吗?
如果 qemu-img 处理数据的速度远大于 cache 存入磁盘的速度,就会出现内存
资源的配置范围管理(LimitRange):可以对集群内Request和Limits的配置做一个全局的统一的限制,
相当于批量设置了某一个范围内(某个命名空间)的Pod的资源使用限制。
资源的配额管理(Resource Quotas):
可以为每一个命名空间(namespace)提供一个总体的资源使用限制,通过它可以限制命名空间中某个类型的对象的总数目上限,
也可以设置命名空间中Pod可以使用到的计算资源的总上限。资源的配额管理有效解决了多用户或多个团队公用一个k8s集群时资源有效分配的问题。
一个LimitRange资源对象可以提供的功能
在一个命名空间中实施对每个 Pod 或 Container 最小和最大的资源使用量的限制。
在一个命名空间中实施对每个 PersistentVolumeClaim 能申请的最小和最大的存储空间大小的限制。
在一个命名空间中实施对一种资源的申请值和限制值的比值的控制。
设置一个命名空间中对计算资源的默认申请/限制值,
并且自动的在运行时注入到多个 Container 中
————————————————
container_memory_working_set_bytes = container_memory_usage_bytes - total_inactive_anon - total_inactive_file
memory used =container_memory_usage_bytes - cache
cache = total_inactive_file + total_active_file
PS:kubelet比较container_memory_working_set_bytes和container_spec_memory_limit_bytes来决定oom container
total_inactive_anon、total_inactive_file为非活动内存,可以被交换到磁盘 cache 缓存存储器存储当前保存在内存中的磁盘数据,所以判断container_memory_working_set_bytes会比container_memory_usage_bytes更为准确
https://segmentfault.com/a/1190000021402244?utm_source=tag-newest
https://blog.csdn.net/palet/article/details/82889493
https://zhuanlan.zhihu.com/p/96597715
https://www.ibm.com/support/pages/kubectl-top-pods-and-docker-stats-show-different-memory-statistics
kubectl top 12.5G