Kubernetes排错(七)-节点排错

1、节点 Crash 与 Vmcore 分析

kdump 介绍

目前大多 Linux 发新版都会默认开启 kdump 服务,以方便在内核崩溃的时候, 可以通过 kdump 服务提供的 kexec 机制快速的启用保留在内存中的第二个内核来收集并转储内核崩溃的日志信息(vmcore 等文件), 这种机制需要服务器硬件特性的支持, 不过现今常用的服务器系列均已支持.

如果没有特别配置 kdump,当发生 crash 时,通常默认会将 vmcore 保存到 /var/crash 路径下,也可以查看 /etc/kdump.conf 配置来确认:

$ grep ^path /etc/kdump.conf
path /var/crash

参考:kdump详解-CSDN博客 

快速查看原因

在需要快速了解崩溃原因的时候, 可以简单查看崩溃主机(如果重启成功)的 vmcore-dmesg.txt 文件, 该文件列出了内核崩溃时的堆栈信息, 有助于我们大致了解崩溃的原因, 方便处理措施的决断. 如下所示为生成的日志文件通常的路径:

/var/crash/127.0.0.1-2019-11-11-08:40:08/vmcore-dmesg.txt

2、节点高负载 

1)如何判断节点高负载?

可以通过 top 或 uptime 命令行来确定 load 大小。load 负载判定规则:

  • load负载值 <= 0.7 * CPU 核数:低负载
  • 0.7 * CPU 核数 < load负载值 <= CPU 核数:负载存在压力
  • load负载值 > CPU 核数: 高负载

2)排查思路

观察监控:通常不是因为内核 bug 导致的高负载,在系统卡死之前从操作系统监控一般能看出一些问题,可以观察下系统各项监控指标与load监控指标的变化趋势,观察是否存在与load监控指标相同变化趋势的指标。

排查现场:如果没有相关监控或监控维度较少不足以查出问题,尝试登录节点分析现场。

注:有时负载过高通常使用 ssh 登录不上,如果可以用 vnc,可以尝试下使用 vnc 登录。

3)排查现场思路

load avg 可以认为是 R状态线程数和D状态线程数的总和 (R 代表需要 cpu,是 cpu 负载。 D 通常代表需要 IO,是 IO 负载),因此一般导致load负载高基本是CPU或者IO。

简单判断办法:

ps -eL -o lwp,pid,ppid,state,comm | grep -E " R | D "

然后统计一下各种状态多少个进程,看看是 D 多还是 R多。

如果是长时间 D多,可以进一步查看进程堆栈看看 D 多的原因是什么,如果是存在大量写请求,可以考虑业务请求数据量调整批次大小,多批次小数据量写入,同时优化磁盘落盘的频率。

cat /proc/<PID>/stack

如果是大量进程/线程在 R 状态,那就是同时需要 CPU 的进程/线程数过多,CPU 忙不过来了,可以利用 perf 分析程序在忙什么,但此时可以考虑业务扩容或者机器调大CPU核数。

perf -p <PID>

4)线程数量过多

如果 load 高但 CPU 利用率不高,通常是同时 running 的进程/线程数过多,排队等 CPU 切换的进程/线程较多。

通常在 load 高时执行任何命令都会非常卡,因为执行这些命令也都意味着要创建和执行新的进程,所以下面排查过程中执行命令时需要耐心等待。

看系统中可创建的进程数实际值:

cat /proc/sys/kernel/pid_max

修改方式: sysctl -w kernel.pid_max=65535

通过以下命令统计当前 PID 数量:

ps -eLf | wc -l

如果数量过多,可以大致扫下有哪些进程,如果有大量重复启动命令的进程,就可能是这个进程对应程序的 bug 导致。

还可以通过以下命令统计线程数排名:

printf "NUM\tPID\tCOMMAND\n" && ps -eLf | awk '{$1=null;$3=null;$4=null;$5=null;$6=null;$7=null;$8=null;$9=null;print}' | sort |uniq -c |sort -rn | head -10

找出线程数量较多的进程,可能就是某个容器的线程泄漏,导致 PID 耗尽。

随便取其中一个 PID,用 nsenter 进入进程 netns:

nsenter -n --target <PID>

然后执行 ip a 看下 IP 地址,如果不是节点 IP,通常就是 Pod IP,可以通过 kubectl get pod -o wide -A | grep <IP> 来反查进程来自哪个 Pod。

5)陷入内核态过久

有些时候某些 CPU 可能会执行耗时较长的内核态任务,比如大量创建/销毁进程,回收内存,需要较长时间 reclaim memory,必须要执行完才能切回用户态,虽然内核一般会有 migration 内核线程将这种负载较高的核上的任务迁移到其它核上,但也只能适当缓解,如果这种任务较多,整体的 CPU system 占用就会较高,影响到用户态进程任务的执行,对于业务来说,就是 CPU 不够用,处理就变慢,发生超时。

CPU 内核态占用的 Prometheus 查询语句:

sum(irate(node_cpu_seconds_total{instance="10.10.1.14",mode="system"}[2m]

6)IO 高负载

系统如果出现 IO WAIT 高,说明 IO 设备的速度跟不上 CPU 的处理速度,CPU 需要在那里干等,这里的等待实际也占用了 CPU 时间,导致系统负载升高,可能就会影响业务进程的处理速度,导致业务超时。

如何判断IO处于高负载?

使用 top 命令看下当前负载:

top - 19:42:06 up 23:59,  2 users,  load average: 34.64, 35.80, 35.76
Tasks: 679 total,   1 running, 678 sleeping,   0 stopped,   0 zombie
Cpu(s): 15.6%us,  1.7%sy,  0.0%ni, 74.7%id,  7.9%wa,  0.0%hi,  0.1%si,  0.0%st
Mem:  32865032k total, 30989168k used,  1875864k free,   370748k buffers
Swap:  8388604k total,     5440k used,  8383164k free,  7982424k cachedPID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND9783 mysql     20   0 17.3g  16g 8104 S 186.9 52.3   3752:33 mysqld5700 nginx     20   0 1330m  66m 9496 S  8.9  0.2   0:20.82 php-fpm6424 nginx     20   0 1330m  65m 8372 S  8.3  0.2   0:04.97 php-fpm

%wa (wait) 表示 IO WAIT 的 cpu 占用,默认看到的是所有核的平均值,要看每个核的 %wa 值需要按下 "1":

top - 19:42:08 up 23:59,  2 users,  load average: 34.64, 35.80, 35.76
Tasks: 679 total,   1 running, 678 sleeping,   0 stopped,   0 zombie
Cpu0  : 29.5%us,  3.7%sy,  0.0%ni, 48.7%id, 17.9%wa,  0.0%hi,  0.1%si,  0.0%st
Cpu1  : 29.3%us,  3.7%sy,  0.0%ni, 48.9%id, 17.9%wa,  0.0%hi,  0.1%si,  0.0%st
Cpu2  : 26.1%us,  3.1%sy,  0.0%ni, 64.4%id,  6.0%wa,  0.0%hi,  0.3%si,  0.0%st
Cpu3  : 25.9%us,  3.1%sy,  0.0%ni, 65.5%id,  5.4%wa,  0.0%hi,  0.1%si,  0.0%st
Cpu4  : 24.9%us,  3.0%sy,  0.0%ni, 66.8%id,  5.0%wa,  0.0%hi,  0.3%si,  0.0%st
Cpu5  : 24.9%us,  2.9%sy,  0.0%ni, 67.0%id,  4.8%wa,  0.0%hi,  0.3%si,  0.0%st
Cpu6  : 24.2%us,  2.7%sy,  0.0%ni, 68.3%id,  4.5%wa,  0.0%hi,  0.3%si,  0.0%st
Cpu7  : 24.3%us,  2.6%sy,  0.0%ni, 68.5%id,  4.2%wa,  0.0%hi,  0.3%si,  0.0%st
Cpu8  : 23.8%us,  2.6%sy,  0.0%ni, 69.2%id,  4.1%wa,  0.0%hi,  0.3%si,  0.0%st
Cpu9  : 23.9%us,  2.5%sy,  0.0%ni, 69.3%id,  4.0%wa,  0.0%hi,  0.3%si,  0.0%st
Cpu10 : 23.3%us,  2.4%sy,  0.0%ni, 68.7%id,  5.6%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu11 : 23.3%us,  2.4%sy,  0.0%ni, 69.2%id,  5.1%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu12 : 21.8%us,  2.4%sy,  0.0%ni, 60.2%id, 15.5%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu13 : 21.9%us,  2.4%sy,  0.0%ni, 60.6%id, 15.2%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu14 : 21.4%us,  2.3%sy,  0.0%ni, 72.6%id,  3.7%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu15 : 21.5%us,  2.2%sy,  0.0%ni, 73.2%id,  3.1%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu16 : 21.2%us,  2.2%sy,  0.0%ni, 73.6%id,  3.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu17 : 21.2%us,  2.1%sy,  0.0%ni, 73.8%id,  2.8%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu18 : 20.9%us,  2.1%sy,  0.0%ni, 74.1%id,  2.9%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu19 : 21.0%us,  2.1%sy,  0.0%ni, 74.4%id,  2.5%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu20 : 20.7%us,  2.0%sy,  0.0%ni, 73.8%id,  3.4%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu21 : 20.8%us,  2.0%sy,  0.0%ni, 73.9%id,  3.2%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu22 : 20.8%us,  2.0%sy,  0.0%ni, 74.4%id,  2.8%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu23 : 20.8%us,  1.9%sy,  0.0%ni, 74.4%id,  2.8%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:  32865032k total, 30209248k used,  2655784k free,   370748k buffers
Swap:  8388604k total,     5440k used,  8383164k free,  7986552k cached

wa 通常是 0%,如果经常在 1% 之上,说明存储设备的速度已经太慢,无法跟上 cpu 的处理速度。

IO高负载如何排查? 

使用 iostat 检查设备是否 hang 住?​

iostat -xhd 2

如果有 100% 的 %util 的设备,说明该设备基本 hang 住了

观察高 IO 的磁盘读写情况

# 捕获 %util 超过 90 时 vdb 盘的读写指标,每秒检查一次
while true; do iostat -xhd | grep -A1 vdb | grep -v vdb | awk '{if ($NF > 90){print $0}}'; sleep 1s; done

如果读写流量或 IOPS 不高,但 %util 不高,通常是磁盘本身有问题了,需要检查下磁盘。 在云上托管的 k8s 集群通常就使用的云厂商的云盘(比如腾讯云CBS),可以拿到磁盘 ID 反馈下。

如果读写流量或 IOPS 高,继续下面的步骤排查出哪些进程导致的 IO 高负载。

查看哪些进程占住磁盘

fuser -v -m /dev/vdb

查找 D 状态的进程

D 状态 (Disk Sleep) 表示进程正在等待 IO,不可中断,正常情况下不会保持太久,如果进程长时间处于 D 状态,通常是设备故障

ps -eo pid,ppid,stat,command## 捕获 D 状态的进程
while true; do ps -eo pid,ppid,stat,command | awk '{if ($3 ~ /D/) {print $0}}'; sleep 0.5s; done

观察高 IO 进程

iotop -oP
# 展示 I/O 统计,每秒更新一次
pidstat -d 1
# 只看某个进程
pidstat -d 1 -p 3394470

使用 pidstat 统计

timeout 10 pidstat -dl 3 > io.txt
cat io.txt | awk '{if ($6>2000||$5>2000)print $0}'

使用 ebpf 抓高 IOPS 进程

安装 bcc-tools:

yum install -y bcc-tools

分析:

$ cd /usr/share/bcc/tools
$ ./biosnoop 5 > io.txt
$ cat io.txt | awk '{print $3,$2,$4,$5}' | sort | uniq -c | sort -rn | head -106850 3356537 containerd vdb R1294 3926934 containerd vdb R864 1670 xfsaild/vdb vdb W578 3953662 kworker/u180:1 vda W496 3540267 logsys_cfg_cli vdb R459 1670 xfsaild/vdb vdb R354 3285936 php-fpm vdb R340 3285934 php-fpm vdb R292 2952592 sap1001 vdb R273 324710 python vdb R
$ pstree -apnhs 3356537
systemd,1 --switched-root --system --deserialize 22└─containerd,3895└─{containerd},3356537    
$ timeout 10 strace -fp 3895 > strace.txt 2>&1
# vdb 的 IOPS 高,vdb 挂载到了 /data 目录,这里过滤下 "/data"
$ grep "/data" strace.txt | tail -10
[pid 19562] newfstatat(AT_FDCWD, "/data/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/6974/fs/data/log/monitor/snaps/20211010/ps-2338.log", {st_mode=S_IFREG|0644, st_size=6509, ...}, AT_SYMLINK_NOFOLLOW) = 0
[pid 19562] newfstatat(AT_FDCWD, "/data/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/6974/fs/data/log/monitor/snaps/20211010/ps-2339.log", {st_mode=S_IFREG|0644, st_size=6402, ...}, AT_SYMLINK_NOFOLLOW) = 0
[pid 19562] newfstatat(AT_FDCWD, "/data/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/6974/fs/data/log/monitor/snaps/20211010/ps-2340.log", {st_mode=S_IFREG|0644, st_size=6509, ...}, AT_SYMLINK_NOFOLLOW) = 0
[pid 19562] newfstatat(AT_FDCWD, "/data/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/6974/fs/data/log/monitor/snaps/20211010/ps-2341.log", {st_mode=S_IFREG|0644, st_size=6509, ...}, AT_SYMLINK_NOFOLLOW) = 0
[pid 19562] newfstatat(AT_FDCWD, "/data/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/6974/fs/data/log/monitor/snaps/20211010/ps-2342.log", {st_mode=S_IFREG|0644, st_size=6970, ...}, AT_SYMLINK_NOFOLLOW) = 0
[pid 19562] newfstatat(AT_FDCWD, "/data/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/6974/fs/data/log/monitor/snaps/20211010/ps-2343.log", {st_mode=S_IFREG|0644, st_size=6509, ...}, AT_SYMLINK_NOFOLLOW) = 0
[pid 19562] newfstatat(AT_FDCWD, "/data/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/6974/fs/data/log/monitor/snaps/20211010/ps-2344.log", {st_mode=S_IFREG|0644, st_size=6402, ...}, AT_SYMLINK_NOFOLLOW) = 0
[pid 19562] newfstatat(AT_FDCWD, "/data/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/6974/fs/data/log/monitor/snaps/20211010/ps-2345.log",  <unfinished ...>
[pid 19562] newfstatat(AT_FDCWD, "/data/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/6974/fs/data/log/monitor/snaps/20211010/ps-2346.log", {st_mode=S_IFREG|0644, st_size=7756, ...}, AT_SYMLINK_NOFOLLOW) = 0
[pid 19562] newfstatat(AT_FDCWD, "/data/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/6974/fs/data/log/monitor/snaps/20211010/ps-2347.log", Process 3895 detached
$ grep "/data" strace.txt > data.txt
# 合并且排序,自行用脚本分析下哪些文件操作多
$ cat data.txt | awk -F '"' '{print $2}' | sort | uniq -c | sort -n > data-sorted.txt

7)如果负载太高导致机器完全无法操作怎么办? 

此情况下建议直接重启。

3、磁盘爆满

1)什么情况下磁盘可能会爆满 ?

kubelet 有 gc 和驱逐机制,通过以下参数:

  • --image-gc-high-threshold
  • --image-gc-low-threshold
  • --eviction-hard--eviction-soft
  • --eviction-minimum-reclaim

控制 kubelet 的 gc 和驱逐策略来释放磁盘空间,如果配置正确的情况下,磁盘一般不会爆满。

通常导致爆满的原因可能是配置不正确或者节点上有其它非 K8S 管理的进程在不断写数据到磁盘占用大量空间导致磁盘爆满。

2)磁盘爆满会有什么影响 ?

影响 K8S 运行我们主要关注 kubelet 和容器运行时这两个最关键的组件,它们所使用的目录通常不一样:

  • kubelet 一般不会单独挂盘,直接使用系统磁盘,因为通常占用空间不会很大;
  • 容器运行时单独挂盘的场景比较多,一般情况下会单独挂盘。

当磁盘爆满的时候我们也要看 kubelet 和 容器运行时使用的目录是否在这个磁盘,通过 df 命令可以查看磁盘挂载点。

3)容器运行时使用的目录所在磁盘爆满

如果容器运行时使用的目录所在磁盘空间爆满,可能会造成容器运行时无响应,比如 docker,执行 docker 相关的命令一直 hang 住, kubelet 日志也可以看到 PLEG unhealthy,因为 CRI 调用 timeout,当然也就无法创建或销毁容器,通常表现是 Pod 一直 ContainerCreating 或 一直 Terminating。

docker 默认使用的目录主要有:

  • /var/run/docker: 用于存储容器运行状态,通过 dockerd 的 --exec-root 参数指定。
  • /var/lib/docker: 用于持久化容器相关的数据,比如容器镜像、容器可写层数据、容器标准日志输出、通过 docker 创建的 volume 等

Pod 启动可能报类似下面的事件:

  Warning  FailedCreatePodSandBox    53m                 kubelet, 172.22.0.44  Failed create pod sandbox: rpc error: code = DeadlineExceeded desc = context deadline exceeded
  Warning  FailedCreatePodSandBox  2m (x4307 over 16h)  kubelet, 10.179.80.31  (combined from similar events): Failed create pod sandbox: rpc error: code = Unknown desc = failed to create a sandbox for pod "apigateway-6dc48bf8b6-l8xrw": Error response from daemon: mkdir /var/lib/docker/aufs/mnt/1f09d6c1c9f24e8daaea5bf33a4230de7dbc758e3b22785e8ee21e3e3d921214-init: no space left on device
  Warning  Failed   5m1s (x3397 over 17h)  kubelet, ip-10-0-151-35.us-west-2.compute.internal  (combined from similar events): Error: container create failed: container_linux.go:336: starting container process caused "process_linux.go:399: container init caused \"rootfs_linux.go:58: mounting \\\"/sys\\\" to rootfs \\\"/var/lib/dockerd/storage/overlay/051e985771cc69f3f699895a1dada9ef6483e912b46a99e004af7bb4852183eb/merged\\\" at \\\"/var/lib/dockerd/storage/overlay/051e985771cc69f3f699895a1dada9ef6483e912b46a99e004af7bb4852183eb/merged/sys\\\" caused \\\"no space left on device\\\"\""

Pod 删除可能报类似下面的事件:

Normal  Killing  39s (x735 over 15h)  kubelet, 10.179.80.31  Killing container with id docker://apigateway:Need to kill Pod

4)kubelet 使用的目录所在磁盘爆满

如果 kubelet 使用的目录所在磁盘空间爆满(通常是系统盘),新建 Pod 时连 Sandbox 都无法创建成功,因为 mkdir 将会失败,通常会有类似这样的 Pod 事件:

  Warning  UnexpectedAdmissionError  44m                 kubelet, 172.22.0.44  Update plugin resources failed due to failed to write checkpoint file "kubelet_internal_checkpoint": write /var/lib/kubelet/device-plugins/.728425055: no space left on device, which is unexpected.

kubelet 默认使用的目录是 /var/lib/kubelet, 用于存储插件信息、Pod 相关的状态以及挂载的 volume (比如 emptyDirConfigMapSecret),通过 kubelet 的 --root-dir 参数指定。

5)如何分析磁盘占用 ?

如果运行时使用的是 Docker,请参考:分析 Docker 磁盘占用-CSDN博客

6)如何恢复 ?

如果容器运行时使用的 Docker,我们无法直接重启 dockerd 来释放一些空间,因为磁盘爆满后 dockerd 无法正常响应,停止的时候也会卡住。我们需要先手动清理一点文件腾出空间好让 dockerd 能够停止并重启。

可以手动删除一些 docker 的 log 文件或可写层文件,通常删除 log:

$ cd /var/lib/docker/containers
$ du -sh * # 找到比较大的目录
$ cd dda02c9a7491fa797ab730c1568ba06cba74cecd4e4a82e9d90d00fa11de743c
$ cat /dev/null > dda02c9a7491fa797ab730c1568ba06cba74cecd4e4a82e9d90d00fa11de743c-json.log.9 # 删除log文件

注意: 使用 cat /dev/null > 方式删除而不用 rm,因为用 rm 删除的文件,docker 进程可能不会释放文件,空间也就不会释放;log 的后缀数字越大表示越久远,先删除旧日志。

然后将该 node 标记不可调度,并将其已有的 pod 驱逐到其它节点,这样重启 dockerd 就会让该节点的 pod 对应的容器删掉,容器相关的日志(标准输出)与容器内产生的数据文件(没有挂载 volume, 可写层)也会被清理:

kubectl drain <node-name>

重启 dockerd:

systemctl restart dockerd
# or systemctl restart docker

等重启恢复,pod 调度到其它节点,排查磁盘爆满原因并清理和规避,然后取消节点不可调度标记:

kubectl uncordon <node-name>

7)如何规避 ?

正确配置 kubelet gc 和 驱逐相关的参数,即便到达爆满地步,此时节点上的 pod 也都早就自动驱逐到其它节点了,不会存在 Pod 一直 ContainerCreating 或 Terminating 的问题。

4、PID 爆满

1)如何判断 PID 耗尽

首先要确认当前的 PID 限制,检查全局 PID 最大限制:

cat /proc/sys/kernel/pid_max

也检查下线程数限制:

cat /proc/sys/kernel/threads-max

再检查下当前用户是否还有 ulimit 限制最大进程数。

确认当前实际 PID 数量,检查当前用户的 PID 数量:

ps -eLf | wc -l

如果发现实际 PID 数量接近最大限制说明 PID 就可能会爆满导致经常有进程无法启动,低版本内核可能报错: Cannot allocate memory,这个报错信息不准确,在内核 4.1 以后改进了: fork: report pid reservation failure properly · torvalds/linux@35f71bc · GitHub

2)如何解决

临时调大 PID 和线程数限制:

echo 65535 > /proc/sys/kernel/pid_max
echo 65535 > /proc/sys/kernel/threads-max

永久调大 PID 和线程数限制:

echo "kernel.pid_max=65535 " >> /etc/sysctl.conf && sysctl -p
echo "kernel.threads-max=65535 " >> /etc/sysctl.conf && sysctl -p

k8s 1.14 支持了限制 Pod 的进程数量: Process ID Limiting for Stability Improvements in Kubernetes 1.14 | Kubernetes

参考:如何限制pod 进程/线程数量?-CSDN博客

5、判断 arp_cache 是否溢出​

node 内核日志会有有下面的报错:

arp_cache: neighbor table overflow!

查看当前 arp 记录数:

$ arp -an | wc -l
1335

查看 arp gc 阀值:

$ sysctl -a | grep gc_thresh
net.ipv4.neigh.default.gc_thresh1 = 128
net.ipv4.neigh.default.gc_thresh2 = 512
net.ipv4.neigh.default.gc_thresh3 = 1024
net.ipv6.neigh.default.gc_thresh1 = 128
net.ipv6.neigh.default.gc_thresh2 = 512
net.ipv6.neigh.default.gc_thresh3 = 1024

当前 arp 记录数接近 gc_thresh3 比较容易 overflow,因为当 arp 记录达到 gc_thresh3 时会强制触发 gc 清理,当这时又有数据包要发送,并且根据目的 IP 在 arp cache 中没找到 mac 地址,这时会判断当前 arp cache 记录数加 1 是否大于 gc_thresh3,如果没有大于就会 时就会报错: arp_cache: neighbor table overflow!

解决方案

调整节点内核参数,将 arp cache 的 gc 阀值调高 (/etc/sysctl.conf):

net.ipv4.neigh.default.gc_thresh1 = 80000
net.ipv4.neigh.default.gc_thresh2 = 90000
net.ipv4.neigh.default.gc_thresh3 = 100000

分析是否只是部分业务的 Pod 的使用场景需要节点有比较大的 arp 缓存空间。

如果不是,就需要调整所有节点内核参数。

如果是,可以将部分 Node 打上标签,比如:

kubectl label node host1 arp_cache=large

然后用 nodeSelector 或 nodeAffnity 让这部分需要内核有大 arp_cache 容量的 Pod 只调度到这部分节点,推荐使用 nodeAffnity,yaml 示例:

  template:spec:affinity:nodeAffinity:requiredDuringSchedulingIgnoredDuringExecution:nodeSelectorTerms:- matchExpressions:- key: arp_cacheoperator: Invalues:- large

参考:K8S node ARP 表爆满 如何优化-CSDN博客

6、inotify 资源耗尽

inotify详解参考:linux inotify 资源详解-CSDN博客

1)inotify 耗尽的危害

如果 inotify 资源耗尽,kubelet 创建容器将会失败:

Failed to watch directory "/sys/fs/cgroup/blkio/system.slice": inotify_add_watch /sys/fs/cgroup/blkio/system.slice/var-lib-kubelet-pods-d111600d\x2dcdf2\x2d11e7\x2d8e6b\x2dfa163ebb68b9-volumes-kubernetes.io\x7esecret-etcd\x2dcerts.mount: no space left on device

2)查看 inotify watch 的限制

每个 linux 进程可以持有多个 fd,每个 inotify 类型的 fd 可以 watch 多个目录,每个用户下所有进程 inotify 类型的 fd 可以 watch 的总目录数有个最大限制,这个限制可以通过内核参数配置: fs.inotify.max_user_watches

查看最大 inotify watch 数:

$ cat /proc/sys/fs/inotify/max_user_watches
8192

3)查看进程的 inotify watch 情况

使用下面的脚本查看当前有 inotify watch 类型 fd 的进程以及每个 fd watch 的目录数量,降序输出,带总数统计:

#!/usr/bin/env bash
#
# Copyright 2019 (c) roc
#
# This script shows processes holding the inotify fd, alone with HOW MANY directories each inotify fd watches(0 will be ignored).
total=0
result="EXE PID FD-INFO INOTIFY-WATCHES\n"
while read pid fd; do \exe="$(readlink -f /proc/$pid/exe || echo n/a)"; \fdinfo="/proc/$pid/fdinfo/$fd" ; \count="$(grep -c inotify "$fdinfo" || true)"; \if [ $((count)) != 0 ]; thentotal=$((total+count)); \result+="$exe $pid $fdinfo $count\n"; \fi
done <<< "$(lsof +c 0 -n -P -u root|awk '/inotify$/ { gsub(/[urw]$/,"",$4); print $2" "$4 }')" && echo "total $total inotify watches" && result="$(echo -e $result|column -t)\n" && echo -e "$result" | head -1 && echo -e "$result" | sed "1d" | sort -k 4rn;

示例输出:

total 7882 inotify watches
EXE                                         PID    FD-INFO                INOTIFY-WATCHES
/usr/local/qcloud/YunJing/YDEyes/YDService  25813  /proc/25813/fdinfo/8   7077
/usr/bin/kubelet                            1173   /proc/1173/fdinfo/22   665
/usr/bin/ruby2.3                            13381  /proc/13381/fdinfo/14  54
/usr/lib/policykit-1/polkitd                1458   /proc/1458/fdinfo/9    14
/lib/systemd/systemd-udevd                  450    /proc/450/fdinfo/9     13
/usr/sbin/nscd                              7935   /proc/7935/fdinfo/3    6
/usr/bin/kubelet                            1173   /proc/1173/fdinfo/28   5
/lib/systemd/systemd                        1      /proc/1/fdinfo/17      4
/lib/systemd/systemd                        1      /proc/1/fdinfo/18      4
/lib/systemd/systemd                        1      /proc/1/fdinfo/26      4
/lib/systemd/systemd                        1      /proc/1/fdinfo/28      4
/usr/lib/policykit-1/polkitd                1458   /proc/1458/fdinfo/8    4
/usr/local/bin/sidecar-injector             4751   /proc/4751/fdinfo/3    3
/usr/lib/accountsservice/accounts-daemon    1178   /proc/1178/fdinfo/7    2
/usr/local/bin/galley                       8228   /proc/8228/fdinfo/10   2
/usr/local/bin/galley                       8228   /proc/8228/fdinfo/9    2
/lib/systemd/systemd                        1      /proc/1/fdinfo/11      1
/sbin/agetty                                1437   /proc/1437/fdinfo/4    1
/sbin/agetty                                1440   /proc/1440/fdinfo/4    1
/usr/bin/kubelet                            1173   /proc/1173/fdinfo/10   1
/usr/local/bin/envoy                        4859   /proc/4859/fdinfo/5    1
/usr/local/bin/envoy                        5427   /proc/5427/fdinfo/5    1
/usr/local/bin/envoy                        6058   /proc/6058/fdinfo/3    1
/usr/local/bin/envoy                        6893   /proc/6893/fdinfo/3    1
/usr/local/bin/envoy                        6950   /proc/6950/fdinfo/3    1
/usr/local/bin/galley                       8228   /proc/8228/fdinfo/3    1
/usr/local/bin/pilot-agent                  3819   /proc/3819/fdinfo/5    1
/usr/local/bin/pilot-agent                  4244   /proc/4244/fdinfo/5    1
/usr/local/bin/pilot-agent                  5901   /proc/5901/fdinfo/3    1
/usr/local/bin/pilot-agent                  6789   /proc/6789/fdinfo/3    1
/usr/local/bin/pilot-agent                  6808   /proc/6808/fdinfo/3    1
/usr/local/bin/pilot-discovery              6231   /proc/6231/fdinfo/3    1
/usr/local/bin/sidecar-injector             4751   /proc/4751/fdinfo/5    1
/usr/sbin/acpid                             1166   /proc/1166/fdinfo/6    1
/usr/sbin/dnsmasq                           7572   /proc/7572/fdinfo/8    1

4)调整 inotify watch 限制

如果看到总 watch 数比较大,接近最大限制,可以修改内核参数调高下这个限制。

临时调整:

sudo sysctl fs.inotify.max_user_watches=524288

永久生效:

echo "fs.inotify.max_user_watches=524288" >> /etc/sysctl.conf && sysctl -p

打开 inotify_add_watch 跟踪,进一步 debug inotify watch 耗尽的原因:

echo 1 >> /sys/kernel/debug/tracing/events/syscalls/sys_exit_inotify_add_watch/enable

7、soft lockup (内核软死锁)

1)内核报错

Oct 14 15:13:05 VM_1_6_centos kernel: NMI watchdog: BUG: soft lockup - CPU#5 stuck for 22s! [runc:[1:CHILD]:2274]

2)原因

发生这个报错通常是内核繁忙 (扫描、释放或分配大量对象),分不出时间片给用户态进程导致的,也伴随着高负载,如果负载降低报错则会消失。

3)什么情况下会导致内核繁忙

短时间内创建大量进程 (可能是业务需要,也可能是业务bug或用法不正确导致创建大量进程)

4)如何优化?

 

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

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

相关文章

【QT】QT中的软键盘设计

QT的软键盘设计 1.软键盘制作步骤2.介绍有关函数的使用3.出现的编译错误及解决办法示例代码1&#xff1a;按键事件实现软键盘现象&#xff1a;示例代码2&#xff1a;按键事件实现软键盘&#xff08;加特殊按键&#xff09;现象&#xff1a; 软键盘移植到新的工程的步骤&#xf…

【LaTeX+VSCode本地Win11编译教程】

LaTeXVSCode本地编译教程参考视频&#xff1a; LaTeXVSCode本地编译教程 下面提供一种Win11的Latex环境配置和设置方案&#xff0c;首先vscode安装参考博客&#xff1a;【VscodeGit教程】&#xff0c;然后准备安装Latex相关组件 在 https://miktex.org/download 下载 miktex 并…

2025五一杯数学建模ABC题赛题已出

2025五一杯数学建模ABC题赛题已出 A: B: C:

Springclound常用五大组件及其使用原理

注册中心Eureka Eureka-Server&#xff1a;就是服务注册中心&#xff08;可以是一个集群&#xff09;&#xff0c;对外暴露自己的地址。 提供者&#xff1a;启动后向Eureka注册自己信息&#xff08;地址&#xff0c;服务名称等&#xff09;&#xff0c;并且定期进行服务续约 …

Docker —— 隔离的基本操作(2)

Docker —— 隔离的基本操作&#xff08;2&#xff09; unshareunshare 命令详解基本语法常用选项常用示例实际应用场景注意事项与 Docker 的关系1. 执行命令2. 修改主机名3. 退出命名空间4. 验证宿主机主机名关键原理类比 Docker 容器总结 实战操作一&#xff08;PID 隔离&…

Java List分页工具

PageUtil.java import com.google.common.collect.Lists; import com.jd.platform.hotkey.dashboard.common.domain.Page; import org.springframework.util.CollectionUtils;import java.util.ArrayList; import java.util.List;public class PageUtil {/*** 通用分页工具类*…

中阳策略:如何从K线行为中提取交易逻辑信号?

中阳策略&#xff1a;如何从K线行为中提取交易逻辑信号&#xff1f; 在量化趋势研究中&#xff0c;中阳形态常被视作市场动能变化的重要标志。它不仅代表价格的强势上行&#xff0c;更隐含着主力资金换手与情绪转换的信号。将“中阳”这一结构元素抽象为模型中的“强动能突破”…

Java SE(8)——继承

1.继承的概念&作用 在Java中&#xff0c;继承是面向对象编程的三大基本特性之一&#xff08;还有封装和多态&#xff09;&#xff0c;允许一个类&#xff08;子类/继承类&#xff09;继承另一个类&#xff08;父类/基类&#xff09;的属性和方法 继承的核心目的是&#xf…

Python爬虫(18)反爬攻防战:动态IP池构建与代理IP实战指南(突破95%反爬封禁率)

目录 引言一、背景&#xff1a;为什么代理IP是爬虫的“第二生命”&#xff1f;1.1 反爬系统的IP检测三把刀1.2 代理IP的核心价值 二、基础实战&#xff1a;快速搭建代理IP系统2.1 免费代理IP的获取与筛选2.2 代理IP的智能容错机制 三、高阶攻防&#xff1a;突破企业级反爬封锁3…

LFU算法解析

文章目录 LFU缓存中关键变量的访问与更新机制1. min_freq - 最小频率访问时机更新时机更新示例 2. capacity - 缓存容量访问时机更新时机访问示例 3. key_to_node - 键到节点的映射访问时机更新时机更新示例 4. freq_to_dummy - 频率到链表哑节点的映射访问时机更新时机更新示例…

ByteArrayInputStream 类详解

ByteArrayInputStream 类详解 ByteArrayInputStream 是 Java 中用于从字节数组读取数据的输入流&#xff0c;位于 java.io 包。它允许将内存中的字节数组当作输入流来读取&#xff0c;是处理内存数据的常用工具。 1. 核心特性 内存数据源&#xff1a;从字节数组&#xff08;b…

rvalue引用()

一、先确定基础:左值(Lvalue)和右值(Rvalue) 理解Rvalue引用,首先得搞清楚左值和右值的概念。 左值(Lvalue):有明确内存地址的表达式,可以取地址。比如变量名、引用等。 复制代码 int a = 10; // a是左值 int& ref = a; // ref也是左值右值(Rval…

吴恩达深度学习作业 RNN模型——字母级语言模型

一. 简单复习一下RNN RNN RNN适用于处理序列数据&#xff0c;令是序列的第i个元素&#xff0c;那么就是一个长度为的序列&#xff0c;NLP中最常见的元素是单词&#xff0c;对应的序列是句子。 RNN使用同一个神经网络处理序列中的每一个元素。同时&#xff0c;为了表示序列的…

基于python的哈希查表搜索特定文件

Python有hashlib库&#xff0c;支持多种哈希算法&#xff0c;比如MD5、SHA1、SHA256等。通常SHA256比较安全&#xff0c;但MD5更快&#xff0c;但可能存在碰撞风险&#xff0c;得根据自己需求决定。下面以SHA256做例。 import hashlib import os from typing import Dict, Lis…

idea创建springboot项目无法创建jdk8原因及多种解决方案

idea创建springboot项目无法创建jdk8原因及多种解决方案 提示&#xff1a;帮帮志会陆续更新非常多的IT技术知识&#xff0c;希望分享的内容对您有用。本章分享的是springboot的使用。前后每一小节的内容是存在的有&#xff1a;学习and理解的关联性。【帮帮志系列文章】&#x…

【C++进阶十】多态深度剖析

【C进阶十】多态深度剖析 1.多态的概念及条件2.虚函数的重写3.重写、重定义、重载区别4.C11新增的override 和final5.抽象类6.虚表指针和虚表6.1什么是虚表指针6.2指向谁调用谁&#xff0c;传父类调用父类&#xff0c;传子类调用子类 7.多态的原理8.单继承的虚表状态9.多继承的…

面向网络安全的开源 大模型-Foundation-Sec-8B

1. Foundation-Sec-8B 整体介绍 Foundation-Sec-8B 是一个专注于网络安全领域的大型语言模型 (LLM),由思科的基础人工智能团队 (Foundation AI) 开发 。它基于 Llama 3.1-8B 架构构建,并通过在一个精心策划和整理的网络安全专业语料库上进行持续预训练而得到增强 。该模型旨在…

Python爬虫的基础用法

Python爬虫的基础用法 python爬虫一般通过第三方库进行完成 导入第三方库&#xff08;如import requests &#xff09; requests用于处理http协议请求的第三方库,用python解释器中查看是否有这个库&#xff0c;没有点击安装获取网站url&#xff08;url一定要解析正确&#xf…

WHAT - Tailwind CSS + Antd = MetisUI组件库

文章目录 Tailwind 和 Antd 组件库MetisUI 组件库 Tailwind 和 Antd 组件库 在 WHAT - Tailwind 样式方案&#xff08;不写任何自定义样式&#xff09; 中我们介绍了 Tailwind&#xff0c;至于 Antd 组件库&#xff0c;我们应该都耳熟能详&#xff0c;官网地址&#xff1a;htt…

Day 4:牛客周赛Round 91

好久没写了&#xff0c;问题还蛮多的。听说这次是苯环哥哥出题 F题 小苯的因子查询 思路 考虑求因子个数&#xff0c;用质因数分解&#xff1b;奇数因子只需要去掉质数为2的情况&#xff0c;用除法。 这里有个比较妙的细节是&#xff0c;提前处理出数字x的最小质因数&#xff0…