你是否遇到过这种情况: Kubernetes 集群中,有的节点负载高企,频频告警,而其他节点却资源闲置,无所事事?这种“忙闲不均”的现象不仅浪费资源,更可能成为系统稳定性的隐患。本文将深入剖析其背后的核心原因——Kubernetes 调度器的工作机制,并提供一套行之有效的治理“三板斧”。
图1:Kubernetes调度器与集群架构图

调度器的核心机制:两阶段决策
K8s 调度器 (kube-scheduler) 并非随机或凭感觉分配 Pod,而是遵循一个严谨的 两阶段流程 :
-
🔍 过滤 (Filtering):硬性指标筛选
- 核心问题:“哪些节点有资格运行这个 Pod?”
- 检查项:节点的
Request(资源预留)是否满足?Taints(污点)Pod 是否能容忍?
- 关键局限:此阶段仅依据 Pod 声明的
Request 值进行判断,完全不关心节点实际的 CPU/内存负载水位。
-
🏆 打分 (Scoring):优选最佳节点
- 核心问题:“在符合条件的节点中,哪个是最优选择?”
- 默认策略:
LeastAllocated (最少分配)。该策略倾向于将 Pod 调度到当前已分配资源最少的节点上,旨在理论上实现集群资源的负载均衡。
负载不均的头号杀手:不合理的 Request 设置
既然默认策略是“最少分配”,为何还会出现忙闲不均?最普遍的原因在于 Request 设置不合理,导致调度器的决策与运行时实际情况严重脱节。
| 现象 |
原因分析 |
后果 |
| Request 设置过低 |
调度器按 0.1 核的资源预留安排节点,但 Pod 实际运行平均消耗 2 核。 |
调度时节点显示“空闲”,运行时 Pod 直接打爆节点,造成负载畸高。 |
| Request 与 Limit 差距过大 |
调度基于保守的 Request,但运行时 Pod 可利用 Limit 进行弹性伸缩,资源占用激增。 |
节点压力随时间推移不可控地升高,初始均衡被破坏。 |
静态调度的局限性:一次性决策
Kubernetes 的原生调度是一个静态的、一次性的决策过程。
- 🔒 绑定即终身:Pod 一旦被调度绑定到某个节点,除非容器崩溃、Pod 被删除或被主动驱逐,否则绝不会被 K8s 主动迁移到其他节点。
- 📉 碎片化堆积:随着集群长期运行和业务的缓慢扩容,Pod 的分布容易形成“碎片化”。早期节点可能堆积了大量 Pod,而后期新加入的节点却非常空闲,历史调度决策的惯性导致了资源分布不均。
治理三板斧
要根治集群忙闲不均,需要从调度源头、强制规则和动态平衡三方面入手。
第一斧:治本之策 —— 修正 Request
修正 Workload 的 Request 设置是解决所有调度问题的基石。
- ✅ 最佳实践:
Request 应设置为应用在正常稳态运行时的平均资源消耗水位。
- 💡 原理:只有向调度器提供真实的资源需求预估,它才能做出正确的“最少分配”决策。
- 🚫 常见误区:不要指望
Limit 来控制调度。Limit 是运行时约束和防止内存泄漏的防线,调度器完全不依赖它进行决策。
第二斧:强制打散 —— 拓扑分布约束
使用 TopologySpreadConstraints(拓扑分布约束) 来主动干预 Pod 的分布策略,这是进行集群资源优化的强力工具。
第三斧:自动重平衡 —— Descheduler
Kubernetes 原生不具备“重调度”能力,需要引入社区组件 Descheduler 来填补这一空白。
- 👮 角色:集群的“巡逻员”。
- 🔄 工作机制:定期扫描集群 -> 识别高负载节点或 Pod 分布不均的情况 -> 主动驱逐(Evict) 符合条件的 Pod。
- ✨ 最终效果:被驱逐的 Pod 会被其控制器(如 Deployment)重新创建,并再次进入调度队列。此时,结合修正后的
Request 和分布约束策略,它们将被重新分配到更空闲的节点上,从而实现动态的集群负载平衡。
理解 Kubernetes 调度机制是掌握 云原生 应用部署的关键一步。通过合理配置资源请求、利用拓扑约束和引入动态平衡工具,你可以有效治理集群的“忙闲不均”问题,提升资源利用率和系统稳定性。如果你想与更多开发者交流此类运维实践,欢迎来云栈社区一起探讨。
|