资源调度优化实战:地理调度、亲和/反亲和与定制调度器,别再把集群当“老虎机”
资源调度优化实战:
地理调度、亲和/反亲和与定制调度器,别再把集群当“老虎机”
我是 Echo_Wish,一个在运维这条路上,被调度坑过、救过火、背过锅的老运维。
我先说一句可能有点扎心的话:
90% 的集群“资源不够”,不是机器不够,而是调度太随缘。
很多团队的真实状态是这样的👇
-
机器买了一堆
-
集群也上了
-
Kubernetes 也部署了
-
结果:
- 有的节点快被压死
- 有的节点在“养老”
- 跨地域访问延迟飙升
- 一出故障就是“玄学”
为什么?
因为调度策略从来没认真想过。
今天这篇文章,咱不讲调度器源码(那玩意看完只会更焦虑),我只围绕三个真正能救命的实战点聊清楚:
- 地理调度:让流量少走弯路
- 亲和 / 反亲和:让 Pod 知道该跟谁混、该躲谁
- 定制调度器:当默认调度真的不懂你业务时
咱用运维人能听懂的方式讲。
一、地理调度:别再让“北京用户请求广州机器”
1️⃣ 这是个真实到离谱的问题
我遇到过一个系统:
- 用户主要在 华东
- 机器分布在 北京 + 上海
- 服务部署随缘
结果就是:
- 用户在上海
- 请求被调度到北京
- RTT 高、超时多、投诉多
开发第一反应:
“是不是 JVM GC 有问题?”
运维一看:
“哥们,你这请求在全国旅游。”
2️⃣ 地理调度的核心思想很简单
一句话总结:
请求在哪,服务尽量在哪
在 Kubernetes 里,地理信息本质上就是 Node Label。
kubectl label node node-shanghai region=shanghai
kubectl label node node-beijing region=beijing
3️⃣ Pod 侧约束:我只想待在“本地”
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
nodeSelector:
region: shanghai
这是最简单粗暴的地理调度。
适合场景:
- 单地域服务
- 边缘计算
- CDN 辅助服务
4️⃣ 更现实的玩法:优先就近,而不是“非此即彼”
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: region
operator: In
values:
- shanghai
意思是:
优先上海,不行再说
这才是生产该有的态度。
📌 Echo_Wish 的感受
地理调度不是“优化”,而是“止血”
你不做,用户体验迟早替你付出代价。
二、亲和 / 反亲和:Pod 也是“社交动物”
1️⃣ 为什么 Pod 需要“亲疏远近”?
现实中有三类需求非常常见:
-
强依赖组件:
- Web ↔ Cache
- API ↔ Sidecar
-
高可用隔离:
- 同一服务的副本不能在同一台机器
-
资源竞争隔离:
- CPU 怪兽和 IO 怪兽别住一起
如果你全靠默认调度:
👉 等着事故找你吧
2️⃣ Pod 亲和:兄弟,咱住近点
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: redis
topologyKey: kubernetes.io/hostname
含义是:
这个 Pod 必须和 redis 在同一节点
适合场景:
- 本地缓存
- 高频 RPC
- Sidecar 模式
3️⃣ Pod 反亲和:兄弟,对不起,咱得分开住
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: order-service
topologyKey: kubernetes.io/hostname
这个配置,救过无数系统的命。
它能保证:
- 同一个服务的副本
- 不会被调度到同一节点
节点挂一个,服务还活着。
4️⃣ 强约束 vs 软约束,别一刀切
preferredDuringSchedulingIgnoredDuringExecution:
这是我个人最推荐的写法。
理由很简单:
可用性 > 完美性
很多事故,都是“约束太严格,结果调度不出来 Pod”。
📌 Echo_Wish 的一句话总结
亲和是为了性能,反亲和是为了命
能不用反亲和的系统,说明你还没被打过。
三、定制调度器:当默认调度器真的不懂你业务
1️⃣ 什么时候你才需要它?
我先劝退一波人:
80% 的集群,不需要自定义调度器
但如果你有以下情况之一👇
- GPU / FPGA / 专用卡
- 特殊网络拓扑
- 强 SLA / 强优先级
- 成本感知调度(抢占 + 计费)
那默认调度器真的不懂你。
2️⃣ 最低成本方式:Scheduler Extender
--scheduler-extender-url=http://extender:8080
Extender 负责两件事:
- Filter:哪些节点不能用
- Score:哪些节点更合适
示例逻辑(伪代码):
def score(nodes, pod):
for node in nodes:
if node.has_gpu and pod.need_gpu:
score[node] += 100
if node.cpu_usage > 80:
score[node] -= 50
3️⃣ 真·定制调度器(慎重)
spec:
schedulerName: my-scheduler
然后你自己实现:
- 队列
- 过滤
- 打分
- 绑定
我说句大实话:
这一步不是技术难,是责任重
一旦出问题:
- 全集群 Pod 卡住
- 恢复成本极高
📌 我的真实建议
能靠 Label + Affinity 解决的,
千万别上定制调度器。
四、把调度当“系统设计”,而不是 YAML 技巧
很多人学调度,学的是:
- 字段
- 参数
- 示例
但真正该学的是:
- 你的业务怕什么?
- 是延迟?
- 是单点?
- 是成本?
- 是资源争抢?
然后反推:
- 地理调度解决“远”
- 反亲和解决“死”
- 定制调度解决“特殊”
五、写在最后:调度,是运维真正的“内功”
我常跟新人说一句话:
不会调度的运维,
迟早会被“资源不够”这四个字压垮。
而真正成熟的运维,会越来越少喊:
- “再买点机器”
而是多问一句: - “调度是不是在浪费资源?”
- 点赞
- 收藏
- 关注作者
评论(0)