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 (比如 emptyDir
, ConfigMap
, Secret
),通过 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)如何优化?
相关文章:
Kubernetes排错(七)-节点排错
1、节点 Crash 与 Vmcore 分析 kdump 介绍 目前大多 Linux 发新版都会默认开启 kdump 服务,以方便在内核崩溃的时候, 可以通过 kdump 服务提供的 kexec 机制快速的启用保留在内存中的第二个内核来收集并转储内核崩溃的日志信息(vmcore 等文件), 这种机制需要服务…...
《架构安全原则》解锁架构安全新密码
The Open Group最新发布的《架构安全原则》标准中文版为企业架构、技术架构、解决方案架构以及安全架构领域的专业人员提供了一套系统化、可落地的安全设计准则。这一权威文件旨在帮助组织在数字化转型的复杂环境中构建既安全又敏捷的架构体系,其内容与TOGAF标准、N…...
生物化学笔记:神经生物学概论10 运动节律的控制 运动时脑内活动 运动系统疾病及其治疗(帕金森、亨廷顿)
运动节律的控制 运动时脑内活动 运动系统疾病及其治疗 口服多巴胺无法穿越“血脑屏障”,进不到脑子里去,其前体(原材料)能进入血脑屏障。一直吃药,机体会偷懒。另一方面,会影响脑子其他部分。 损毁也只能暂时解决,黑质…...
DDR在PCB布局布线时的注意事项及设计要点
一、布局注意事项 控制器与DDR颗粒的布局 靠近原则:控制器与DDR颗粒应尽量靠近,缩短时钟(CLK)、地址/控制线(CA)、数据线(DQ/DQS)的走线长度,减少信号延迟差异。 分组隔…...
Paramiko源码深入解析
Paramiko是一个基于Python的SSHv2协议实现库,支持远程命令执行、文件传输(SFTP)和安全隧道功能。以下是对其源码的深入解析,涵盖核心模块、关键流程及实现细节。 1. 核心模块与结构 Paramiko的源码结构围绕SSH协议的各个层次设计…...
音频感知动画新纪元:Sonic让你的作品更生动
前言 在现代肖像动画领域,如何精准地控制画面中的焦点,确保声音和画面完美契合,已成为了一个十分值得探索的话题。于是,Sonic 方法应运而生,这种创新的音频感知技术,旨在让肖像动画中的焦点能够与音频内容同步,从而提升整体的沉浸感和表现力。在ComfyUI 中实现这一功能…...
uniapp开发06-视频组件video的使用注意事项
uniapp开发-视频组件video的使用注意事项!实际项目开发中,经常会遇到视频播放的业务需求。下面简单讲解一下,uniapp官方提供的视频播放组件video的常见参数和实际效果。 1:先看代码: <!--视频组件的使用展示-->…...
英伟达语音识别模型论文速读:Fast Conformer
Fast Conformer:一种具有线性可扩展注意力的高效语音识别模型 一、引言 Conformer 模型因其结合了深度可分离卷积层和自注意力层的优势,在语音处理任务中取得了出色的性能表现。然而,Conformer 模型存在计算和内存消耗大的问题,…...
利用jQuery 实现多选标签下拉框,提升表单交互体验
在 Web 开发中,表单设计常常需要支持用户选择多个选项的场景。传统的多选框或下拉菜单在处理大量选项时,可能会影响界面美观和操作便捷性。这时,多选标签下拉框就成为了一种优雅的解决方案。本文将详细介绍如何通过 HTML、CSS 和 jQuery 实现…...
基于 HTML 和 CSS 实现的 3D 翻转卡片效果
一、引言 在网页设计中,为了增加用户的交互体验和视觉吸引力,常常会运用一些独特的效果。本文将详细介绍一个基于 HTML 和 CSS 实现的 3D 翻转卡片效果,通过对代码的剖析,让你了解如何创建一个具有立体感的卡片,在鼠标…...
【阿里云大模型高级工程师ACP学习笔记】2.9 大模型应用生产实践 (下篇)
特别说明:由于这一章节是2025年3月官方重点更新的部分,新增内容非常多,因此我不得不整理成上、下两篇,方便大家参考。 学习目标 备考阿里云大模型高级工程师ACP认证的这部分内容,旨在深入理解大模型应用在安全合规方面的要求,掌握模型部署相关要点,提升实际操作和应对复…...
MVC、MVP、MVVM三大架构区别
1、MVC架构 M(Model):主要处理数据的存储、获取、解析。 V(View):即Fragement、Activity、View等XML文件 C(Controller):主要功能为控制View层数据的显示,…...
期末代码Python
以下是 学生信息管理系统 的简化版代码示例(控制台版本,使用文件存储数据),包含核心功能: 1. 定义学生类 class Student: def __init__(self, sid, name, score): self.sid sid # 学号 self.name name # 姓名 self.s…...
ecat总线6000段定义
1ecat总线 不适合新手学习,我复习用的。 can和ecat是一家的,就跟C和C的关系。 参考CIA402定义 2 PDOr⬇️ 主站发送到终端伺服。 有4组,0x1600 3 PDOt⬆️ 伺服驱动器发送到主站。 我记得有4组,但这款伺服只有2组。 4 速度模…...
数据管理能力成熟度评估模型(DCMM)全面解析:标准深度剖析与实践创新
文章目录 一、DCMM模型的战略价值与理论基础1.1 DCMM的本质与战略定位1.2 DCMM的理论基础与创新点 二、DCMM模型的系统解构与逻辑分析2.1 八大能力域的有机关联与系统架构2.2 五级成熟度模型的内在逻辑与演进规律 三、DCMM八大能力域的深度解析与实践创新3.1 数据战略ÿ…...
Python精进系列:random.uniform 函数的用法详解
目录 🔍 一、引言📌 二、函数定义与参数说明✅ 函数定义⚙️ 参数说明 🧪 三、使用示例1️⃣ 生成单个随机数2️⃣ 生成多个随机数3️⃣ 生成二维坐标 🎯 四、应用场景🧪 模拟实验📊 数据采样🎮…...
观察者模式(Observer Pattern)
🧠 观察者模式(Observer Pattern) 观察者模式是一种行为型设计模式。它定义了一种一对多的依赖关系,使得当一个对象的状态发生变化时,所有依赖于它的对象都会得到通知并自动更新。通常用于事件驱动的编程场景中。 &am…...
【论文阅读】Joint Deep Modeling of Users and Items Using Reviews for Recommendation
Joint Deep Modeling of Users and Items Using Reviews for Recommendation 题目翻译:利用评论对用户和项目进行联合深度建模进行推荐 原文地址:点这里 关键词: DeepCoNN、推荐系统、卷积神经网络、评论建模、协同建模、评分预测、联合建模…...
webpack 的工作流程
Webpack 的工作流程可以分为以下几个核心步骤,我将结合代码示例详细说明每个阶段的工作原理: 1. 初始化配置 Webpack 首先会读取配置文件(默认 webpack.config.js),合并命令行参数和默认配置。 // webpack.config.js…...
Linux 常用指令详解
Linux 操作系统中有大量强大的命令行工具,下面我将分类介绍一些最常用的指令及其用法。 ## 文件与目录操作 ### 1. ls - 列出目录内容 ls [选项] [目录名] 常用选项: - -l:长格式显示(详细信息) - -a:显…...
DXFViewer进行中 : ->封装OpenGL -> 解析DXF直线
DXFViewer进行中,目标造一个dxf看图工具。. 目标1:封装OpenGL,实现正交相机及平移缩放功能 Application.h #pragma once #include <string> #include <glad/glad.h> #include <GLFW/glfw3.h> #include "../Core/TimeStamp.h" #includ…...
多序列比对软件MAFFT介绍
MAFFT(Multiple Alignment using Fast Fourier Transform)是一款广泛使用且高效的多序列比对软件,由日本京都大学的Katoh Kazutaka等人开发,最早发布于2002年,并持续迭代优化至今。 它支持从几十条到上万条核酸或蛋白质序列的快速比对,同时在准确率和计算效率之间提供灵…...
基于 HTML5 Canvas 实现图片旋转与下载功能
一、引言 在 Web 开发中,经常会遇到需要对图片进行处理并提供下载功能的需求。本文将深入剖析一段基于 HTML5 Canvas 的代码,该代码实现了图片的旋转(90 度和 180 度)以及旋转后图片的下载功能。通过对代码的解读,我们…...
学习路线(机器人系统)
机器人软件/系统学习路线(从初级到专家) 初级阶段(6-12个月)基础数学编程基础机器人基础概念推荐资源 中级阶段(1-2年)机器人运动学机器人动力学控制系统感知系统推荐资源 高级阶段(2-3年&#…...
基于EFISH-SCB-RK3576工控机/SAIL-RK3576核心板的网络安全防火墙技术方案(国产化替代J1900的全栈技术解析)
基于EFISH-SCB-RK3576/SAIL-RK3576的网络安全防火墙技术方案 (国产化替代J1900的全栈技术解析) 一、硬件架构设计 流量处理核心模块 多核异构架构: 四核Cortex-A72(2.3GHz):处理深度…...
基于 jQuery 实现复选框全选与选中项查询功能
在 Web 开发中,复选框是常见的交互元素,尤其是在涉及批量操作、数据筛选等场景时,全选功能和选中项查询功能显得尤为重要。本文将介绍如何使用 HTML、CSS 和 jQuery 实现一个具备全选、反选以及选中项查询功能的复选框组,帮助开发…...
Python中的JSON库,详细介绍与代码示例
目录 1. 前言 2. json 库基本概念 3. json 的适应场景 4. json 库的基本用法 4.1 导 json入 模块 4.2 将 Python 对象转换为 JSON 字符串 4.3 将 JSON 字符串转换为 Python 对象 4.4 将 Python 对象写入 JSON 文件 4.5 从 JSON 文件读取数据 4.6 json 的其他方法 5.…...
tensorflow 调试
tensorflow 调试 tf.config.experimental_run_functions_eagerly(True) 是 TensorFlow 中的一个配置函数,它的作用是: 让 tf.function 装饰的函数以 Eager 模式(即时执行)运行,而不是被编译成图(Graph&…...
iptables的基本选项及概念
目录 1.按保护范围划分: 2.iptables 的基础概念 4个规则表: 5个规则链: 3.iptables的基础选项 4.实验 1.按保护范围划分: 主机防火墙:服务范围为当前一台主机 input output 网络防火墙:服务范围为防…...
使用AI 将文本转成视频 工具 介绍
🎬 文字生成视频工具 一款为自媒体创作者设计的 全自动视频生成工具,输入文本即可输出高质量视频,大幅提升内容创作效率。视频演示:https://leeseean.github.io/Text2Video/?t23 ✨ 功能亮点 功能模块说明📝 智能分…...
Python生活手册-NumPy数组创建:从快递分拣到智能家居的数据容器
一、快递分拣系统(列表/元组转换) 1. 快递单号录入(np.array()) import numpy as np快递单号入库系统 快递单列表 ["SF123", "JD456", "EMS789"] 快递数组 np.array(快递单列表) print(f"…...
Cmake编译wxWidgets3.2.8
一、下载库源代码 去wxWidgets - Browse /v3.2.8 at SourceForge.net下载wxWidgets-3.2.8.7z 二、建立目录结构 1、在d:\codeblocks目录里新建wxWidgets_Src目录 2、把文件解压到该目录 3、建立 CB目录,并在该目录下分别建立 Debug 和 Release目录 三、使用Cmake…...
2.在Openharmony写hello world
原文链接:https://kashima19960.github.io/2025/03/21/openharmony/2.在Openharmony写hello%20world/ 前言 Openharmony 的第一个官方例程的是教你在Hi3861上编写hello world程序,这个例程相当简单编写 Hello World”程序,而且步骤也很省略&…...
「OC」源码学习——对象的底层探索
「OC」源码学习——对象的底层探索 前言 上次我们说到了源码里面的调用顺序,现在我们继续了解我们上一篇文章没有讲完的关于对象的内容函数,完整了解对象的产生对于isa赋值以及内存申请的内容 函数内容 先把_objc_rootAllocWithZone函数的内容先贴上…...
从0开始学习大模型--Day01--大模型是什么
初识大模型 在平时遇到问题时,我们总是习惯性地去运用各种搜索引擎如百度、知乎、CSDN等平台去搜索答案,但由于搜索到的内容质量参差不齐,检索到的内容只是单纯地根据关键字给出内容,往往看了几个网页都找不到答案;而…...
202533 | SpringBoot集成RocketMQ
SpringBoot集成RocketMQ极简入门 一、基础配置(3步完成) 添加依赖 <!-- pom.xml --> <dependency><groupId>org.apache.rocketmq</groupId><artifactId>rocketmq-spring-boot-starter</artifactId><version&g…...
大模型学习专栏-导航页
概要 本专栏是小编系统性调研大模型过程中沉淀的知识结晶,涵盖技术原理、实践应用、前沿动态等多维度内容。为助力读者高效学习,特整理此导航页,以清晰脉络串联核心知识点,搭建起系统的大模型学习框架,助您循序渐进掌握…...
互联网大厂Java面试:从Java SE到微服务的全栈挑战
场景概述 在这场面试中,谢飞机,一个搞笑但有些水的程序员,面对的是一位严肃的大厂面试官李严。面试官的目的是考察谢飞机在Java全栈开发,特别是微服务架构中的技术能力。面试场景设定在内容社区与UGC领域,模拟一个社交…...
2024年408真题及答案
2024年计算机408真题 2024年计算机408答案 2024 408真题下载链接 2024 408答案下载链接...
【datawhaleAI春训营】楼道图像分类
目录 图像分类任务的一般处理流程为什么使用深度学习迁移学习 加载实操环境的库加载数据集,默认data文件夹存储数据将图像类别进行编码自定义数据读取加载预训练模型模型训练,验证和预测划分验证集并训练模型 修改baseline处理输入数据选择合适的模型Ale…...
Unity:输入系统(Input System)与持续检测键盘按键(Input.GetKey)
目录 Unity 的两套输入系统: 🔍 Input.GetKey 详解 🎯 对比:常用的输入检测方法 技术底层原理(简化版) 示例:角色移动 为什么会被“新输入系统”替代? Unity 的两套输入系统&…...
day04_计算机常识丶基本数据类型转换
计算机常识 计算机如何存储数据 计算机底层只能识别二进制。计算机底层只识别二进制是因为计算机内部的电子元件只能识别两种状态,即开和关,或者高电平和低电平。二进制正好可以用两种状态来表示数字和字符,因此成为了计算机最基本的表示方…...
rvalue引用()
一、先确定基础:左值(Lvalue)和右值(Rvalue) 理解Rvalue引用,首先得搞清楚左值和右值的概念。 左值(Lvalue):有明确内存地址的表达式,可以取地址。比如变量名、引用等。 复制代码 int a = 10; // a是左值 int& ref = a; // ref也是左值右值(Rval…...
【Web3】上市公司利用RWA模式融资和促进业务发展案例
香港典型案例 朗新科技(充电桩RWA融资) 案例概述:2024年8月,朗新科技与蚂蚁数科合作,通过香港金管局“Ensemble沙盒”完成首单新能源充电桩资产代币化融资,募资1亿元人民币。技术实现:蚂蚁链提供…...
什么是IIC通信
IIC(Inter-Integrated Circuit),即IC,是一种串行通信总线,由飞利浦公司在1980年代开发,主要用于连接主板、嵌入式系统或手机中的低速外围设备1。IIC协议采用多主从架构,允许多个主设备和从设备连接在同一总线上进行通信。 IIC协议的工作原理: IIC协议使用两根信号线进…...
网络原理 TCP/IP
1.应用层 1.1自定义协议 客户端和服务器之间往往进行交互的是“结构化”数据,网络传输的数据是“字符串”“二进制bit流”,约定协议的过程就是把结构化”数据转成“字符串”或“二进制bit流”的过程. 序列化:把结构化”数据转成“字符串”…...
掌纹图像识别:解锁人类掌纹/生物识别的未来——技术解析与前沿数据集探索
概述 掌纹识别是一种利用手掌表面独特的线条、纹理和褶皱模式进行身份认证的生物识别技术。它具有非侵入性、高准确性和难以伪造的特点,被广泛应用于安全认证领域。以下将结合提供的链接,详细介绍掌纹识别的技术背景、数据集和研究进展。 提供的链接分析 香港理工大学掌纹数…...
【FPGA开发】Xilinx DSP48E2 slice 一个周期能做几次int8乘法或者加法?如何计算FPGA芯片的GOPS性能?
Xilinx DSP48E2 slice 在一个时钟周期内处理 INT8(8 位整数)运算的能力。 核心能力概述 一个 DSP48E2 slice 包含几个关键计算单元: 预加器 (Pre-Adder): 可以执行 A D 或 A - D 操作,其中 A 是 30 位,D 是 27 位。…...
APP 设计中的色彩心理学:如何用色彩提升用户体验
在数字化时代,APP 已成为人们日常生活中不可或缺的一部分。用户在打开一个 APP 的瞬间,首先映入眼帘的便是其色彩搭配,而这些色彩并非只是视觉上的装饰,它们蕴含着强大的心理暗示力量,能够潜移默化地影响用户的情绪、行…...
残差网络实战:基于MNIST数据集的手写数字识别
残差网络实战:基于MNIST数据集的手写数字识别 在深度学习的广阔领域中,卷积神经网络(CNN)一直是处理图像任务的主力军。随着研究的深入,网络层数的增加虽然理论上能提升模型的表达能力,但却面临梯度消失、…...