最近一段时间,因为业务增长飞速同时导致了服务器压力倍增,瞬时压力有时候上升到了100%,此时Node服务器开始变得极不稳定,系统进程频频被kill,甚至导致无法ssh远程登录。
紧急定位问题,最终定位到有以下两点问题,导致内存不足时服务器不稳定。
(1)K8S和docker使用的cgroup 驱动和centos7.5系统守护进程使用的cgroup 驱动不一致
(2)没有为系统进程预留可用的内存
当 Pod 内存不足时,会触发OOM 把 Pod 杀死;但当整个系统内存不足时,就有可能触发系统 OOM,导致整个虚拟机宕机。这时候根据 oom score 来确定优先杀死哪个进程,而 oom_score_adj 又是影响 oom score 的重要参数,其值越低,表示 oom 的优先级越低。
OOM 的优先级如下:
sshd 等 | K8S 管理进程 | guarantee pod | 其它进程 | best effort pod | |
---|---|---|---|---|---|
具体进程 | sshd/dmevented / systemd-udevd | kubelet / docker / journalctl | guarantee pod | 内核 init 进程等 | best effort pod |
oom_score_adj | -1000 | -999 | -998 | 0 | >0 |
best effort pod > 其它进程 > guarantee pod > kubelet/docker 等 > sshd 等。
可以看到守护进程都是优先级最低的,但是为什么还是会被杀死呢?因为我们在安装Kubernetes和Docker定义cgroup驱动时定义为了cgroupfs,因为而centos系统的守护进程的用的是systemd做内存管理的,这两个相当于是两套管理器管理同一个内存资源,同时这两套之间没有通信,所以当高压力的情况cgroupfs会占用服务器的全部资源而不考虑系统进程,而systemd发现系统已经没内存的时候就会根据oom_score_adj 将系统进程給杀掉
在 Linux 上,控制组(CGroup)用于限制分配给进程的资源。
kubelet 和底层容器运行时都需要对接控制组来强制执行 为 Pod 和容器管理资源 并为诸如 CPU、内存这类资源设置请求和限制。若要对接控制组,kubelet 和容器运行时需要使用一个 cgroup 驱动。 关键的一点是 kubelet 和容器运行时需使用相同的 cgroup 驱动并且采用相同的配置。
可用的 cgroup 驱动有两个: