k8s-kublulet-OOM-kill ,容器 OOM , jvm oom故障分析

一  k8s  kubelet OOM kill 基础知识和排查思路

前提:超出容器的内存限制

只要节点有足够的内存资源,那容器就可以使用超过其申请的内存,但是不允许容器使用超过其限制的 资源。如果容器分配了超过限制的内存,这个容器将会被优先结束。如果容器持续使用超过限制的内存, 这个容器就会被终结。如果一个结束的容器允许重启,kubelet就会重启他,但是会出现其他类型的运行错误。

腾讯认为张阳认为 (再limit 和request比例悬殊  增长超出node特殊情况下):

1. 如果Pod的实际使用内存,超过了 Node 的实际内存,肯定会发生驱逐的,有个优先级:先驱逐未设置 request/limit 的pod,再驱逐 request/limit 不相等的pod,最后驱逐 request/limit 相等的pod。
2. 避免的话有几个可以考虑:设置合理的 request 防止在调度层面的不均匀、使用 TKE 的 DynamicScheduler、DeScheduler 插件优化调度策略,让 kube-scheduler 按照真实负载进行调度。

参考:
1. DynamicScheduler:https://cloud.tencent.com/document/product/457/50843
2. DeScheduler:https://cloud.tencent.com/document/product/457/50921腾讯

1 .1  request 和limits

简单来说,

request影响的是k8s的调度,也就是说k8s会保证container所request的资源,在调度时会考虑node是否满足request的条件。

limit则是实际运行时k8s的限制,防止container无限制的占用node的资源。显然的,由于调度时更多的考虑了request而不是limit,那么必然会出现某个node上container的limit总和超过该node资源的情况,此时,k8s针对cpu和memory会由不同的处理。

对于cpu,k8s认为cpu是可压缩的,在应用达到limit时,k8s会减少该容器的调度时间,并不会杀死应用。

对于memory,k8s认为memory是无法压缩的,此时k8s会杀死占用资源超过其request的应用(1.9版本之后的版本)。首当其冲的是没有指定request的container,然后是使用资源超过其request更多的container。同等情况下优先级更低的container更容易被杀死。

1.2 深入优化kubelet OOM 文章:

https://www.cnblogs.com/xuliang666/p/11137128.html

系统参数限制

设置系统内核参数:

1

2

3

vm.overcommit_memory = 0

vm.swappiness = 0

sysctl -p #生效

内核参数overcommit_memory

它是 内存分配策略

可选值:0、1、2。

  • 0, 表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。
  • 1, 表示内核允许分配所有的物理内存,而不管当前的内存状态如何。
  • 2, 表示内核允许分配超过所有物理内存和交换空间总和的内存

设置overcommit_memory = 0.是为了避免系统发生OOM自动杀死进程.

解释:什么是Overcommit和OOM

        Linux对大部分申请内存的请求都回复"yes",以便能跑更多更大的程序。因为申请内存后,并不会马上使用内存。这种技术叫做 Overcommit。当linux发现内存不足时,会发生OOM killer(OOM=out-of-memory)。它会选择杀死一些进程(用户态进程,不是内核线程),以便释放内存。
        当oom-killer发生时,linux会选择杀死哪些进程?选择进程的函数是oom_badness函数(在mm/oom_kill.c中),该 函数会计算每个进程的点数(0~1000)。点数越高,这个进程越有可能被杀死。每个进程的点数跟oom_score_adj有关,而且 oom_score_adj可以被设置(-1000最低,1000最高)。

vm.swappiness = 0 就是限制使用交换分区.应该kubernetes不建议使用交换分区,而且一般是关闭交换分区的.

kubelet进程设置预留内存:

cat /var/lib/kubelet/config.yaml

默认参数

1

2

3

4

5

6

eventRecordQPS: 5

evictionHard:

  imagefs.available: 15%

  memory.available: 100Mi

  nodefs.available: 10%

  nodefs.inodesFree: 5%

内存限制优化:

1

2

3

4

5

evictionHard:

  imagefs.available: 15%

  memory.available: 1Gi    #这里限制节点预留内存

  nodefs.available: 10%

  nodefs.inodesFree: 5%

这里自行百度了解 Kubernetes Eviction Manager工作机制

实在不行 我简单复制粘贴一点内容吧...哭.......

首先,我们来谈一下kubelet通过OOM Killer来回收资源的缺点:

  • System OOM events本来就是对资源敏感的,它会stall这个Node直到完成了OOM Killing Process。
  • 当OOM Killer干掉某些containers之后,kubernetes Scheduler可能很快又会调度一个新的Pod到该Node上或者container 直接在node上restart,马上又会触发该Node上的OOM Killer启动OOM Killing Process,事情可能会没完没了的进行,这可不妙啊。

我们再来看看Kubelet Eviction有何不同:

  • Kubelet通过pro-actively监控并阻止Node上资源的耗尽,一旦触发Eviction Signals,就会直接Fail一个或者多个Pod以回收资源,而不是通过Linux OOM Killer这样本身耗资源的组件进行回收。
  • 这样的Eviction Signals的可配置的,可以做到Pro-actively。
  • 另外,被Evicted Pods会在其他Node上重新调度,而不会再次触发本Node上的再次Eviction。

下面,我们具体来研究一下Kubelet Eviction Policy的工作机制。

  • kubelet预先监控本节点的资源使用,并且阻止资源被耗尽,这样保证node的稳定性。
  • kubelet会预先Fail N(>= 1)个Pod以回收出现紧缺的资源。
  • kubelet会Fail一个Node时,会将Pod内所有Containners都kill掉,并把PodPhase设为Failed。
  • kubelet通过事先人为设定Eviction Thresholds来触发Eviction动作以回收资源。

pod资源限制

就是requests和limits参数设置内存,cpu.按自己需求设置即可.

默认是不限制资源

pod主机亲和性

Kubernetes - GC的镜像自动清理导致的问题

Kubernetes集群随着应用的迭代,会产生很多无用的镜像和容器,因此需要定时清理,分布在每个节点的Kubelet有GC(垃圾收集)的职责,当集群中有断定为垃圾的镜像或容器,那么kubelet会清除掉相关镜像或容器。容器GC间隔为1分钟,镜像GC间隔为5分钟。而这在某些情况下会产生问题,如:私有离线部署环境中,如果某个node节点相关的镜像被清理了,当在这个启动相关容器就会失败,由于是离线,那么拉取镜像也会失败。

解决办法:

  • 搭建离线私有镜像仓库;
  • 关闭Kubernetes的GC对镜像的自动清理行为。

二 容器和jvm层 OOM基础知识 和排查思路

# 排查参考文章:

https://blog.csdn.net/fly910905/article/details/90179225

# 理解Linux  oom 

https://blog.csdn.net/run_for_belief/article/details/83446344

#  jvm oom 八种原因和排查

https://blog.csdn.net/fly910905/article/details/90179225

# 理解 java oom

https://www.cnblogs.com/bhlsheji/p/5330045.html

省略比較小的区域,能够总结JVM占用的内存:
JVM内存 ≈ Java永久代 + Java堆(新生代和老年代) + 线程栈+ Java NIO

你可能感兴趣的:(linux,java,oom)