亲和性规则本身不是bug,但配置不当会让Pod扎堆挤在同一批节点上,形成调度热点。 这个问题在2026年的混部集群和节点异构场景中尤其常见,根源在于节点标签设计粗糙、评分策略单一,以及运维人员对亲和性优先级理解不透彻,下面从现象、原因、排查到解决,一步步拆开看。
亲和性规则是如何悄悄把流量“聚”起来的
调度决策的隐性偏好
Kubernetes调度器在给Pod选节点时,会先过滤满足硬性条件的节点,再给剩余节点打分,亲和性规则(nodeAffinity、podAffinity、podAntiAffinity)在这里扮演“偏好放大器”的角色,一个工作负载设置了requiredDuringSchedulingIgnoredDuringExecution的nodeSelectorTerms,要求节点必须带zone=az1标签,那么调度器只能从az1的节点里挑,如果az1本身只有三台机器,而其他可用区有三十台,流量自然全部压在这三台上。
热点不是瞬间爆发的,而是被规则一步步引导到同一批节点上。 业内专家指出,超过半数的高密度集群调度热点,根因都出在亲和性表达式与节点容量规划脱节。
亲和性规则的“抱团”效应
Pod亲和性(podAffinity)的设计初衷是让相关Pod靠近,比如让缓存和数据服务同节点减少网络延迟,但如果业务方不加区分地对所有工作负载都添加topologyKey: kubernetes.io/hostname的亲和性,那么同一个Deployment的副本会强制分布到同一台节点,更危险的是一组相互依赖的服务同时启用亲和性,形成“抱团式调度”,节点资源瞬间被吃满,其他Pod只能排队。
node亲和性 vs pod亲和性区别是很多运维容易混淆的地方:nodeAffinity是Pod挑节点,podAffinity是Pod挑邻居,前者会导致固定节点过热,后者会导致局部区域过热,实际案例中,后者造成的热点更难定位,因为节点标签没问题,但Pod之间的引力关系把调度路径锁死了。
排查调度热点:先分清是资源不足还是规则作祟
看调度器日志中的“为什么”
当Pod长时间Pending,很多人第一反应是加节点,但更高效的做法是先看调度器的事件记录,用kubectl describe pod <pod-name>可以看到调度失败的原因,如果输出为0/5 nodes are available: 1 node(s) didn't match pod affinity/anti-affinity,基本可以判定是亲和性规则导致无可用节点,另一种情况是Pod被调度到某个节点后,节点CPU或内存使用率很快飙升,但其他节点空闲很多,说明亲和性把Pod集中到了少数节点上。
用Prometheus量化热点程度
打开集群监控,按节点维度统计Pod数量和资源分配率,如果某个节点的Pod数量是其他节点的2倍以上,同时该节点标签与其他节点有明显隔离属性(如不同的rack或zone),大概率是亲和性在起作用,此时检查工作负载的YAML,重点看spec.affinity字段。
排查时建议逐个工作负载做“规则清单”:这类规则是硬约束(required)还是软偏好(preferred)?硬约束会直接导致调度失败,软偏好则会影响打分,让一些节点得分被压低,从而被“冷落”,很多热点是preferred规则累积造成的单个Pod的偏好不致命,但数百个Pod都偏好同一类节点,热点就出来了。

常见误判:把热点归咎于资源碎片
资源碎片(比如内存碎片导致大Pod无法安置)和亲和性热点在现象上有相似之处,都是某个节点装不下Pod,但碎片的特征是各个节点可用资源都不连续,而亲和性热点的特征是部分节点完全空闲,部分节点资源紧张但还能塞下小Pod,用kubectl describe node查看每个节点的Allocatable与Requests差值,如果空闲节点剩余资源远大于Pending Pod所需,却依然调度不上去,那问题就在亲和性规则。
解决调度热点:从改标签到调策略
第一步:梳理并收敛节点标签
亲和性规则依赖的标签越少越好,很多集群里,不同团队各自打了一堆标签,比如rack=A、type=compute、disk=ssd,但没有任何统一规划,这会让调度器面对大量候选节点时只能依赖评分算法,而评分算法本身可能被这些标签误导。操作路径:先通过kubectl get nodes --show-labels列出所有节点标签,再与工作负载的spec.affinity进行比对,删除那些不再使用的标签,或者合并颗粒度,比如zone标签应该与机房对应,而不是与某台物理机编号绑定。
第二步:将硬约束改为软偏好
如果某个业务必须固定在某些节点上(比如GPU节点),保留requiredDuringScheduling;但如果只是为了“尽量靠近”某个服务,把preferredDuringSchedulingIgnoredDuringExecution的权重调低,举个例子,原来用nodeAffinity硬性要求dedicated=bigdata,现在改为preferred并加上weight: 50,调度器就会在其余条件相近时优先选bigdata节点,但不会把它们当作唯一选择,这个改动通常能立刻缓解热点。
第三步:利用Pod反亲和性打散负载
如果热点区域是多个相同副本“自我聚集”导致的,可以给工作负载添加podAntiAffinity,要求同标签的Pod不要落在同一拓扑域。
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values: ["nginx"]
topologyKey: kubernetes.io/hostname
这段配置会让调度器尽量避免把多个app=nginx的Pod放在同一台宿主机上,从而把负载均匀扩散,注意,如果集群节点数量少于副本数,这种反亲和性会导致调度失败,需要配合requiredDuringScheduling使用时要特别小心。
第四步:在混合部署场景下做优先级隔离
2026年不少集群同时跑在线服务和离线任务,在线服务通常要求节点独占或高优先级,而离线任务则可以共享,如果两者都用亲和性规则,比如在线服务强绑定group=A节点,离线任务也强绑定

group=A节点,那热点就无可避免。合理的做法是给不同优先级设置不同拓扑键,在线服务用topologyKey: topology.kubernetes.io/zone(机房级别),离线任务用hostname(节点级别),这样在线服务能在整个机房分散,离线任务也不会挤在同一台机器上,行业共识认为,多可用区部署时,pod亲和性规则应尽量以zone为拓扑边界,不要细化到hostname,否则一个可用区故障就可能拖垮所有关联服务。
从源头避免热点:设计阶段的三个关键选择
节点分组不要“一刀切”
很多团队喜欢把节点按“计算型”和“内存型”简单分类,然后对所有业务都添加nodeAffinity,这样做的问题是,同一个分类下的节点规格可能差异很大,比如内存型节点中有64GB和256GB两种,但标签都是type=mem,调度器不会考虑规格差异,只看标签,导致64GB的节点先被装满,256GB的节点空着。建议:节点标签要体现“规格+用途”两个维度,比如spec=64c256g和usage=ai,而不是笼统的type=mem。
软偏好的权重设计
亲和性规则中的weight值直接影响调度评分,排查热点时,你可能会发现某个规则权重高达200,而其他规则只有10,那么这条规则几乎等同于硬约束。合理范围:关键业务路径上的软偏好权重可以设为100,非关键路径控制在50以下,同时要检查不同Deployment之间的权重是否存在叠加效应如果一百个Deployment都偏好zone=az1,即使每个权重只有10,总分也会压过其他可用区,这种情况下,需要给每个Deployment设置不同的偏好分布,比如50%业务偏好az1,另外50%偏好az2。
定期做调度仿真
不要等到热点发生才去调整,可以用Kubernetes的调度器插件机制写一个简单的模拟器,输入现有节点资源、Pod规格以及所有亲和性规则,输出每个节点的理论分配率,这个操作不需要额外工具,可以通过kube-scheduler的--config配置profile,把score插件日志打开,观察每个候选节点的得分详情,如果发现某个节点长期得分最高,就说明亲和性规则存在系统性倾斜。
kubernetes亲和性配置不当导致调度热点时,日常巡检怎么做
- 每周检查一次
Pending状态的Pod数量,按原因分组,如果Unschedulable数量超过集群Pod总数的1%,就需要关注。 - 使用
kubectl get pods --field-selector=status.phase=Pending快速过滤,再对每个Pending Pod执行describe查看调度事件。 - 把节点使用率数据接入告警,条件设为“单节点CPU使用率超过80%,同时集群平均CPU使用率低于40%”,这是热点最典型的信号。
- 重点检查新上线的业务,尤其是那些复制了老业务YAML并稍作修改就部署的情况亲和性规则很可能被原样保留,而新业务的节点拓扑与老业务完全不同。
实际场景对比:hard和soft规则的热点表现

| 规则类型 | 热点特征 | 定位难度 | 补救成本 |
|---|---|---|---|
| requiredDuringScheduling | Pod无法调度,直接Pending | 低 | 高(需要改规则或加节点) |
| preferredDuringScheduling | Pod能调度,但集中在部分节点 | 高 | 低(调权重或加反亲和) |
| podAffinity | 相关联的Pod扎堆 | 中 | 中(需要重新设计拓扑键) |
| podAntiAffinity | 过度分散导致大规格Pod无法安置 | 中 | 中(需要放宽拓扑键粒度) |
在百度云服务器这样的场景里,如果用户在控制台创建集群时勾选了“启用Pod亲和性”却未进行任何定制,那么默认规则会倾向于把Pod调度到相同可用区以降低跨可用区带宽成本,这本身没问题,但一旦业务流量超过节点承载能力,调度热点就会表现为部分云服务器CPU使用率长期打满,而其他服务器空转,这时候,用户往往以为是云主机规格不够,实际上只要把亲和性的topologyKey从zone改成hostname,或者将硬约束改为软约束,就能均衡负载。
关于亲和性规则调度热点的三个常见疑问
问:为什么我设置了podAntiAffinity,热点问题反而更严重了?
答:反亲和性会把Pod强制分散到不同节点,但如果你只有一个节点拥有满足条件的标签,比如设置topologyKey: failure-domain.beta.kubernetes.io/zone,而集群只在一个可用区部署,那么所有Pod都会尝试抢占这个可用区内的不同节点,当节点数量不够时,调度就会失败或反复重试,反亲和性应该结合节点容量一起规划,单靠它不能解决所有热点问题。
问:nodeAffinity和podAffinity应该如何选择?
答:如果业务需要固定在某些节点上运行,比如GPU计算任务,使用nodeAffinity,如果业务实例之间需要低网络延迟,比如分布式缓存,使用podAffinity,但两者都不应该作为默认配置,对于大多数普通工作负载,建议什么都不加,让调度器基于资源水位自由选择,只有当监控数据证明存在性能瓶颈时,才考虑添加规则。
问:修改亲和性规则后,已经运行的热点Pod会立刻迁移吗?
答:不会。IgnoredDuringExecution意味着规则只在调度时生效,已经运行的Pod不会自动重新调度,你需要手动执行kubectl rollout restart deployment/<name>,让Pod滚动重建,新的调度器才会应用更新后的规则,这是很多运维容易遗漏的一步,改完规则发现热点没缓解,原因就在这里。
说到底,亲和性规则是调度器手里的“方向盘”,用好了能让流量精准流向目的地,用歪了就会把车聚集在同一个加油站前排长队,排查这类问题,先看标签一致性,再看规则类型,最后动态调整权重和拓扑键,只要每次变更前都问一句“这条规则会不会让多个Pod争抢同一个节点”,热点问题就能提前化解。