题干与适用场景
一个无状态服务运行在多个可用区,副本数会从 2 扩到 30。节点故障、扩缩容和滚动发布期间,团队希望避免副本集中在一个故障域,同时不能因为严格分布导致新版本完全无法调度。请设计 topologySpreadConstraints,并说明何时使用 DoNotSchedule、ScheduleAnyway 或反亲和性。
面试官考察什么
- 能否把“高可用”具体化为节点、可用区、区域等故障域目标。
- 能否正确解释
maxSkew、minDomains、topologyKey和whenUnsatisfiable。 - 能否识别标签选择器、缺少拓扑标签和小副本数带来的边界行为。
- 能否把调度约束、PDB、滚动更新、自动扩容和观测放在同一方案中。
回答前要澄清的问题
- 可用区是否真的独立供电、网络和容量?区域故障是否在本次目标内?
- 服务至少需要几个副本才能承受一个故障域丢失?
- 调度失败时是宁可等待、降低可用性,还是允许暂时偏斜?
- 工作负载标签、节点拓扑标签和默认约束是否由平台统一管理?
- 滚动更新期间旧版与新版是否共享同一个
labelSelector?
30 秒回答框架
我会先定义故障域和最小容量,再为节点与可用区分别设置分布约束。关键服务使用受控的 DoNotSchedule,普通或弹性服务使用 ScheduleAnyway 作为软目标;maxSkew 约束同一选择器在 eligible domains 间的差距,minDomains 防止可用域不足时误判。上线前验证标签、扩缩容、滚动发布和单域故障,运行中监控每域副本数、Pending 时长、可用容量和 PDB 中断预算。
分步骤深入解答
第一步:先定义故障域和容量目标
把节点、可用区、区域映射为不同 topologyKey。若服务要承受一个可用区故障,应至少在两个以上可用区保留足够副本;若副本只有 2,无法同时保证三个可用区均匀且任一域故障后仍有两个健康副本。先写出容量不变量,再决定约束强度。
第二步:选择 maxSkew 与 minDomains
maxSkew 表示目标域与全局最小值之间允许的最大差距;DoNotSchedule 下超过差距会让 Pod 保持 Pending。minDomains 用于表达至少需要多少个 eligible domain,避免域数量不足时把全局最小值按零计算。小副本服务应通过演练确认设置不会阻塞发布。
第三步:区分硬约束和软约束
关键控制面或支付服务可以在可用区层使用 DoNotSchedule,把调度失败暴露为容量告警;批处理或可延迟服务可用 ScheduleAnyway,让调度器优先降低 skew 但允许临时偏斜。硬反亲和性适合简单的“不要同域”规则,但多层拓扑和可观测 skew 通常更适合拓扑分布约束。
第四步:保证选择器和标签可信
约束的 labelSelector 必须匹配实际 Pod 模板,否则新 Pod 可能被计算到错误的集合。节点必须带有稳定的 zone、region 和 hostname 标签;缺少标签的节点不会按该拓扑域参与评分。平台应在准入时检查选择器、标签和默认约束,避免团队复制失效 YAML。
第五步:联动发布、PDB 与扩缩容
滚动更新要计算旧版、新版和 maxUnavailable 的叠加容量,避免更新过程中暂时违反故障域目标。PDB 只能限制自愿中断,不能替代跨域调度。自动扩容器应感知 Pending Pod 和各域容量,否则严格约束可能持续等待而不增加可用节点。
第六步:定义故障和降级动作
先演练单节点、单可用区和节点标签丢失,再观察新 Pod 是被拒绝、偏斜调度还是长时间 Pending。关键服务可以暂停低优先级发布、扩容健康域或切换只读模式;不能在生产中临时删除硬约束而不记录风险。降级动作应版本化并可回滚。
第七步:用分布指标验证结果
按工作负载、版本和拓扑域记录副本数、skew、Pending 时长、调度失败原因、可用容量、PDB 中断和请求错误率。压测应覆盖副本从 2 到 30、域容量不均、滚动更新和自动扩容。目标是证明故障域丢失后剩余容量满足 SLO,而不是只证明副本落在不同节点。
高质量示范回答
我会把节点、可用区和区域作为三层故障域,先确定一个可用区丢失后仍需保留的最小副本数。服务 Pod 使用匹配模板标签的 labelSelector,在 hostname 和 zone 层分别设置约束;关键服务的 zone 约束使用较小 maxSkew 与 DoNotSchedule,批处理使用 ScheduleAnyway。当 eligible domains 少于 minDomains 时触发容量告警,而不是静默接受错误分布。滚动更新同时校验 PDB、maxUnavailable 和新旧版本选择器,自动扩容器监听 Pending 原因和域容量。上线先以观测模式运行,随后灰度启用硬约束,并用每域副本数、Pending 时长、故障域演练结果和业务 SLO 作为回滚闸门。
常见错误
- 只写“跨可用区部署”,却没有说明
topologyKey和副本容量。 - 把
maxSkew误解成域之间的绝对副本上限。 - 忽略
labelSelector不匹配,导致约束统计了错误的 Pod 集合。 - 把 PDB 当成调度约束,或认为 PDB 能阻止所有节点故障。
- 对副本数为 2 的服务承诺三个可用区都均匀且任一域故障后不降级。
- 直接删除
DoNotSchedule解决 Pending,却没有记录可用性风险。
追问及应对
追问一:ScheduleAnyway 还有高可用价值吗?
有。它把降低 skew 作为调度偏好,在容量不足时仍允许运行;适合可延迟或有其他冗余的工作负载。关键服务可在高峰前扩容并使用硬约束。
追问二:为什么不全部使用 pod anti-affinity?
反亲和性表达“避免与某些 Pod 同域”,多层拓扑、skew 数值和最小域数量表达较弱。拓扑分布约束更直接描述跨域差距,反亲和性仍适合单一排斥规则。
追问三:minDomains 配错会怎样?
eligible domain 数量不足时,skew 的全局最小值计算可能让约束看起来满足或使 Pod 长时间 Pending。应把域可用性纳入准入检查和容量告警,并在集群版本上确认字段行为。
追问四:滚动发布为什么会破坏分布?
新旧版本可能使用不同标签选择器,或者 maxUnavailable 与 maxSurge 暂时增加某个域的副本。发布前应模拟中间状态并观察每个版本、每个域的 skew。
追问五:节点缺少 zone 标签怎么办?
该节点不会按指定拓扑键正确参与分布。平台应修复节点标签或隔离节点,不能把无标签节点当成独立故障域来承诺容量。
追问六:如何证明一个可用区故障后仍满足 SLO?
执行隔离演练,确认剩余域的可调度容量、健康副本、请求错误率和恢复时间满足目标;同时记录 PDB、Pending 原因和扩容时间,验证从调度到业务指标的完整链路。