导读:本期聚焦于芒果创作的《集群节点总卡顿却找不到瓶颈?这份系统状态排查方法值得收藏》,敬请观看详情。集群节点出现高负载时,排查到底应该从哪个维度入手,很多人容易陷入只看 CPU 和内存的误区。实际上,系统状态是一个综合概念,CPU 使用率、内存水位、磁盘吞吐、inode 耗尽、文件句柄数、网络连接数以及内核日志中的报错都可能是真正的瓶颈所在。本文围绕集群资源与系统状态给出一个可落地的排查框架,从节点底层资源、Kubernetes 调度与驱逐机制、工作负载运行视图等维度展开,并结合常见故障场景给出对应的命令组合与判断依据。内容包含 uptime、vmstat、iostat、kubectl describe node、kubelet 驱逐阈值等常用工具的实战用法,帮助你快速定位是节点资源不足、镜像拉取失败、Pod 反复重启,还是系统参数配置不合理导致的问题,从而避免盲目重启和拍脑袋扩容。

集群节点出现卡顿或者频繁告警的时候,最容易犯的错误是一上来就盯住 CPU 使用率。CPU 高确实是一种异常,但很多时候 CPU 只是表象,真正的压力可能来自磁盘排队、内存回收、句柄耗尽或者网络软中断。系统状态检查要想做得有效率,必须有一套从底层到上层的排查顺序,先分清是节点问题还是集群调度问题,再根据资源类型逐一排除。

集群节点总卡顿却找不到瓶颈?这份系统状态排查方法值得收藏

从系统层快速判断节点是否处于健康状态

任何集群排障的第一步都应该回到节点本身。无论上层是 Kubernetes 还是自研调度系统,底层操作系统一旦出现资源争抢,所有容器和进程都会被拖慢。一个比较高效的切入方式是使用 uptime 查看负载平均值,再结合 CPU 核心数来判断负载是否真的过高。很多人误以为负载均值超过 1 就是有问题,实际上八核机器在负载 6 的时候依然可以正常工作,重点是观察趋势而非绝对值。如果负载在持续爬升,即使当前数值不高,也要警惕演进中的资源瓶颈。

接下来需要把内存和磁盘的检查做细。建议按如下顺序执行一组命令,每条命令解决一个维度的疑问:内存是否够用、内存是否发生换页、磁盘是否繁忙、inode 是否耗尽。使用 free -h 观察 available 列,而不是只盯着 total 和 used,因为 Linux 内核会把空闲内存用作 page cache,used 偏高并不必然代表内存紧张。真正需要警惕的是 swap 的使用量,如果 swap 持续增长且 si/so 列长期不为零,说明内存回收压力已经传导到了磁盘换页层面。

# 查看系统负载均值,判断短时与长期趋势
uptime

# 查看内存总量、可用量与 swap 使用情况
free -h

# 查看内存换页、CPU 上下文切换、IO 等待等关键指标
vmstat 1 5

# 查看磁盘使用率,同时关注 inode 剩余量
df -h
df -i

# 查看块设备级别的读写吞吐与等待时间
iostat -x 1 3

执行完上述命令后,需要重点分析 iostat 输出中的 %utilawait 两列。如果 %util 已接近 100% 而 await 也很高,说明磁盘确实成为瓶颈。如果是 SSD 阵列,%util 达到 100% 时往往伴随明显的写放大效应,此时需要检查是否存在日志型应用在频繁刷盘。对于使用网络存储的集群节点,还要关注 r_awaitw_await 的差距,读等待显著高于写等待,通常意味着存储服务端或网络链路存在问题。

文件句柄数也是一个极易被忽略的指标。容器化应用在频繁创建连接或打开文件时,如果宿主机的 fs.file-max 设置偏小,会引发 Too many open files 一类的报错。此时建议使用 sysctl fs.file-nr 查看已分配句柄数、未使用句柄数与最大句柄数,同时使用 lsof -p 定位到具体进程的句柄占用情况。这里需要特别提醒:句柄数检查不区分进程版本,无论是 Java 应用还是 Nginx 网关,只要句柄耗尽都会导致新连接无法建立。

从集群视角检查资源水位与调度异常

系统层的资源状态确认无误后,下一步要切换到集群视角。在 Kubernetes 环境中,可使用 kubectl describe node 查看节点的资源分配情况,重点观察 Allocated resources 部分。很多实际案例表明,节点的分配率并未达到 100%,但 Pod 依然出现 CPU 节流,这通常是因为可压缩资源的 limit 值导致 cgroup 层面对 CPU 的配额限制。此时需要计算节点的 CPU 请求总量与可分配量之间的关系,并判断是否存在大量的 Burstable Pod 在争抢 CPU 时间片。

除了资源分配率,节点状态与污点也同样值得关注。如果一个节点长时间处于 NotReady 状态,优先排查 kubelet 服务是否存活,以及容器运行时(如 containerd 或 dockerd)是否发生假死。而如果节点显示 MemoryPressureDiskPressure 状态,则说明节点已触发驱逐条件,kubelet 会根据 QoS 等级优先停止 BestEffort 类型的 Pod。理解驱逐机制有助于快速判断哪些 Pod 会先被杀掉,从而确定保护关键业务的方法。

# 查看节点整体状态与污点信息
kubectl get nodes -o wide

# 查看节点的资源分配率、条件状态与驱逐信号
kubectl describe node node-01

# 查看 kubelet 服务的运行状态与最近日志
systemctl status kubelet
journalctl -u kubelet --since "10 minutes ago" --no-pager | grep -i evict

# 查看节点上的全部 Pod 及资源实际使用情况
kubectl top node

# 查看节点各 Pod 的资源消耗排名
kubectl top pod -A --sort-by=cpu | head -20

需要说明的是,kubectl top 依赖 metrics-server 提供数据,如果该组件不可用则无法执行。在没有 metrics-server 的环境里,可以通过 kubectl describe node 中记录的 Non-terminated Pods 数量以及请求量做粗略评估。更精确的做法是登录节点,使用 systemd-cgtop 查看 cgroup 级别的资源消耗,这比单纯依赖 kubectl top 看到的数据更接近真实宿主机视角。如果多个节点同时出现内存紧张,还要检查 kubelet 的 --system-reserved--kube-reserved 参数是否预留了足够资源给系统进程。

对于大规模集群,节点状态检查不能单靠人工执行命令,建议编写一个简洁的巡检脚本,定期采集节点的负载、内存、磁盘与 kubelet 状态。将脚本输出到文件或接入监控系统后,后续排查时只需对比历史趋势,就能快速发现资源使用率的突变点。巡检脚本本身不必过于复杂,可以按如下模式实现,将各维度数据输出为带时间戳的文本记录。

#!/bin/bash
# 定期采集节点核心指标,用于集群资源趋势分析
while true; do
  echo "==== $(date '+%Y-%m-%d %H:%M:%S') ===="
  uptime
  free -m | awk 'NR==1 || NR==2'
  df -h / /var/lib/docker 2>/dev/null
  cat /proc/loadavg
  sleep 60
done

深入工作负载层定位反复重启与启动失败问题

当节点基础资源和调度状态都没有明显异常时,问题往往隐藏在工作负载本身。以 Kubernetes 为例,容器反复进入 CrashLoopBackOff 或长时间处于 Pending 状态,其背后的原因不尽相同。对于 Pending 状态的 Pod,先检查是否存在未满足的节点选择器、资源请求大于节点可分配量、或者存储卷无法挂载等调度限制。对于 CrashLoopBackOff,则需要拿到容器日志和退出码,退出码 137 通常代表被 OOM Killer 杀死,而 143 往往与 SIGTERM 有关。

镜像拉取失败是另一个高频问题。特别在离线环境或使用私有镜像仓库时,ImagePullBackOff 错误会反复出现。处理逻辑很简单:先确认镜像标签是否存在、仓库地址是否可达,再检查节点上的容器运行时凭据配置是否正确。使用 crictl imagescrictl pull 可以绕过 Kubernetes 层直接测试容器运行时的拉取能力,这有助于快速区分是 kubelet 配置问题还是运行时网络问题。

# 查看 Pod 运行状态与所在节点
kubectl get pods -o wide -A | grep -E 'Pending|CrashLoop'

# 查看 Pod 详细事件,关注调度失败或拉取失败原因
kubectl describe pod <pod-name> -n <namespace>

# 查看容器上一次退出的日志
kubectl logs <pod-name> -n <namespace> --previous

# 进入容器后查看进程树与资源占用
kubectl exec -it <pod-name> -n <namespace> -- /bin/sh

# 检查容器运行时侧的镜像与容器状态
crictl ps -a | head -20
crictl images | grep <image-name>
crictl logs <container-id>

容器内部视角与宿主机视角存在明显差异。容器内执行 free -m 看到的内存数据实际上反映的是宿主机的全局内存,而不是容器自身的限制值。正确的方式是读取容器的 cgroup 文件,例如 /sys/fs/cgroup/memory.max/sys/fs/cgroup/memory.current,这些文件记录的是容器真实的内存上限与当前使用量。对于 CPU 同样如此,cat /sys/fs/cgroup/cpu.max 可以查看容器获得的 CPU 配额,据此判断是否因配额过小而导致容器内线程频繁被节流。

在排查 Pod 反复重启的同时,还要注意一个容易忽略的细节:容器内的时区与日志时间戳。很多应用在容器中默认使用 UTC 时间,导致日志时间与监控系统的本地时间对不上,排障时极容易误判事件发生的先后顺序。建议在描述故障时间线时先统一时区口径,将容器日志与节点内核日志的时间戳放在同一参照系下对比。另外,journalctl -k 中的内核日志往往带有 OOM 事件、驱动报错和文件系统异常信息,这些线索对定位系统级故障有决定性作用。

从事件与指标联动中还原故障根因

集群故障很少是单一维度造成的,事件与指标联动分析才能准确还原当时的系统状态。举例来说,节点负载突然飙升时,如果只查看监控系统中的 CPU 曲线,可能只能看到一条平滑上升的线,却无法解释上升的原因。此时需要将节点事件、Pod 调度记录、内核日志以及应用日志四类数据放在同一时间轴上来对照分析。如果监控系统支持标签关联,优先以节点名为维度拉取所有关联数据,而不是单独查看某一个指标。

下面给出一个实战场景:某集群中的一个节点频繁出现 NotReady,每次持续时间约为两分钟后自动恢复。初步检查 CPU 和内存均无异常,但在内核日志中发现 blocked for more than 120 seconds 的提示,说明内核线程被磁盘 I/O 阻塞。进一步排查后发现,该节点存在一个数据清理任务,短时间内产生大量随机写操作,导致磁盘响应时间飙升。这里真正的根因是磁盘 I/O 排队,而不是 CPU 或内存容量不足。

# 查看内核日志中因 IO 阻塞导致的异常事件
journalctl -k --since "1 hour ago" | grep -i "blocked for more than"

# 查看进程的 IO 等待时间与磁盘读写速率
pidstat -d 1 10

# 查看系统平均负载与 CPU 上下文切换的高频指标
vmstat 1 10

# 查看进程级别的上下文切换与运行队列
cat /proc/<pid>/status | grep -E "voluntary|nonvoluntary"

从这个案例可以提炼出一个更为通用的排障思路:不要只做一个统计员,要做一个侦探。每看到一个异常指标,都要追问这个指标的上游是什么。CPU 高要问是哪类进程消耗的,内存高要问是 page cache 还是匿名页占用的,磁盘繁忙要问是读多还是写多、对应哪个应用。只有把指标层层下钻到进程和线程级别,才能把集群资源的排查工作做到真正闭环。

在联动分析过程中,dmesg 也是一个不可忽视的信息来源。内核在检测到 OOM 时会在内核环形缓冲区中记录被终止进程的名称、PID 和内存占用。当 K8s 的 OOMKilled 事件与内核日志的 OOM 记录同时出现时,可以迅速锁定目标进程。需要留意的是,内核日志记录的内容在容器运行时层面可能不会完整呈现给应用,因此需要在宿主机上直接查看。将 dmesg 输出按时间保存为文件,并与容器重启时间对比,是还原根因的常用做法。

把被动救火转化成常态巡检

排障工作如果只停留在故障处理层面,集群的稳定性很难有本质提升。一个成熟的集群运维体系应该把上述排查思路定期化、自动化。例如每周检查一次节点文件句柄数的增长趋势,每天对 kubelet 的错误日志做关键词告警,定期对内核日志中的异常信息做归档分析。主动巡检能帮助团队在资源耗尽之间发现问题,避免将故障放大到用户可感知的层面。

巡检脚本需要结合集群自身特征来定制。例如以运行大数据任务为主的集群,需要重点监控磁盘吞吐和临时目录的空间使用情况;而以在线 Web 服务为主的集群,则要关注连接数、句柄数与 CPU 节流情况。以下巡检脚本模板按天维度运行,将关键数据记录到日志文件,供后续趋势分析使用,同时满足轻量与实用的要求。

#!/bin/bash
# 集群节点日常巡检脚本,建议配合 crontab 每日执行
LOG_DIR="/var/log/cluster-inspect"
mkdir -p $LOG_DIR
DATE=$(date '+%Y%m%d')
LOG_FILE="$LOG_DIR/inspect-$DATE.log"

echo "==== System Load ====" > $LOG_FILE
uptime >> $LOG_FILE
echo "==== Memory ====" >> $LOG_FILE
free -m >> $LOG_FILE
echo "==== Disk Usage ====" >> $LOG_FILE
df -h >> $LOG_FILE
echo "==== Inode Usage ====" >> $LOG_FILE
df -i >> $LOG_FILE
echo "==== Top 10 CPU Processes ====" >> $LOG_FILE
ps -eo user,pid,pcpu,pmem,comm --sort=-pcpu | head -11 >> $LOG_FILE
echo "==== Kubelet Status ====" >> $LOG_FILE
systemctl is-active kubelet >> $LOG_FILE
echo "==== Recent Kernel Errors ====" >> $LOG_FILE
journalctl -k --since "24 hours ago" -p err --no-pager | tail -50 >> $LOG_FILE

最后,还是想强调文档沉淀的重要性。每一次集群资源排障结束之后,都应该把完整的排查过程、关键命令输出、根因分析结论整理成排障文档。长期积累下来,这些文档就是团队最宝贵的知识库。当后续再次出现类似问题时,可以直接检索文档中的关键词,快速匹配到相似的故障特征,从而把平均恢复时间控制在分钟级别。资源检查的目的从来不是看数据,而是通过数据读懂系统当前的状态,并预判下一步可能发生的问题。

集群规模越大,资源状态的复杂度就越高,仅靠单一的监控面板无法覆盖所有视角。将节点系统命令、Kubernetes 对象状态、cgroup 限制、内核日志和进程调度信息结合起来,构建一套完整的检查路径,才能真正掌握集群的实时健康度。对任何一位运维工程师或 SRE 来说,这套方法论比死记硬背某条命令更能应对多变的故障场景。

集群资源系统状态检查性能排障修改时间:2026-08-27 09:00:07

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。