惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

宝玉的分享
宝玉的分享
Engineering at Meta
Engineering at Meta
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园 - 聂微东
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Last Week in AI
Last Week in AI
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 三生石上(FineUI控件)
T
Tailwind CSS Blog
Apple Machine Learning Research
Apple Machine Learning Research
Hugging Face - Blog
Hugging Face - Blog
爱范儿
爱范儿
博客园 - 司徒正美
人人都是产品经理
人人都是产品经理
Jina AI
Jina AI
博客园 - 叶小钗
雷峰网
雷峰网
罗磊的独立博客
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - Franky
WordPress大学
WordPress大学
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
阮一峰的网络日志
阮一峰的网络日志
量子位

博客园 - 张占岭

keycloak~通过用户ID直接置换token keycloak~缓存对象的介绍与作用 wso2-apim-mcp2改版分析 mcp1和mcp2对比 为什么前端项目使用ts比js要多了 多个IDP的用户联合方案的分析 apisix~forward-auth外部认证 apisix~response-rewrite响应头重写 springboot~关于构造方法注入和字段注入的选择 apisix~OpenResty各阶段的介绍 keycloak~aud受众字段的作用及如何生成 wso2~关于workbuddy中mcp在wso2中的授权端点 WEB安全~csrf介绍 WEB安全~DPoP的介绍 WEB安全~csp的介绍 什么是中间人攻击 WEB安全~xss的介绍 k8s~pod资源限制和JVM的XMX配置 关于对wso2和keycloak的token交换的调研 keycloak~实现OAuth 2.0 Token Exchange backstage~实体的介绍及它们的关系 backstage~openapi的接入与protobuf的对比 backstage~将java服务添加到backstage backstage~对接github和gitlab backstage~开始一个backstage应用 apisix~graphQL的支持 wso2几个核心项目介绍 docker~BuildKit的介绍 k8s~secret资源的使用 算法~时间戳计算两个日期是否为同天同时同分
k8s~避免调度资源碎片化
张占岭 · 2026-05-06 · via 博客园 - 张占岭

调度资源碎片化详解

调度资源碎片化是指:由于每个Pod的Request设置不合理,导致节点上虽然实际物理内存还有大量空闲,但因为Request的"虚占"导致无法调度新Pod的现象。

这类似于硬盘文件系统的碎片化——明明总空闲空间很大,但因为没有连续的大块空间,无法存储大文件。


核心概念:Request是"预留",不是"占用"

# 关键理解
resources:
  requests:
    memory: 8Gi   # ← 这是"预留车位",不是"实际停车"
  limits:
    memory: 16Gi  # ← 这是"最大允许停的车辆数"

类比:停车场管理

┌─────────────────────────────────────────────────────┐
│  停车场总车位:32个                                   │
├─────────────────────────────────────────────────────┤
│  每个公司可以"预定"车位(Request)                    │
│  但实际停了几辆车(实际使用)没人管                    │
│                                                      │
│  问题:                                               │
│  - 公司A预定8个车位,实际停了9.5辆车(超停)          │
│  - 公司B预定6个车位,实际停了3辆车                    │
│  - 总预定车位:8+6+... = 26个                        │
│  - 剩余可预定:32-26=6个                             │
│                                                      │
│  实际物理空闲:还有其他6个车位空着?                   │
│  不对!因为公司A超停了1.5辆,实际只空4.5个车位         │
│  但调度系统只看预定数,认为只能再接收6个车位的预定      │
└─────────────────────────────────────────────────────┘

具体例子演示

场景设定

# 节点配置
节点内存:32Gi

# 现有Pod
Pod1: Request=4Gi, Limit=8Gi,  实际使用=3Gi
Pod2: Request=6Gi, Limit=12Gi, 实际使用=5Gi  
Pod3: Request=8Gi, Limit=16Gi, 实际使用=2Gi
你的Pod: Request=8Gi, Limit=16Gi, 实际使用=9.5Gi  # ← 问题Pod

调度器视角(只看Request)

# 调度器计算可调度内存
总节点内存: 32Gi
已分配Request总和: 4+6+8+8 = 26Gi
剩余可调度Request: 32 - 26 = 6Gi

# 调度器结论
"节点只剩下6Gi的调度配额,只能调度Request≤6Gi的Pod"

实际情况(物理内存)

# 真实物理内存使用
Pod1实际: 3Gi
Pod2实际: 5Gi
Pod3实际: 2Gi
你的Pod实际: 9.5Gi
实际总使用: 3+5+2+9.5 = 19.5Gi

# 物理空闲内存
物理空闲: 32 - 19.5 = 12.5Gi

# 矛盾!
物理空闲: 12.5Gi
可调度配额: 6Gi  ← 怎么只有一半?

可视化对比

物理内存实际使用(真实情况):
┌──────────────────────────────────────────────────┐
│ 32GB 物理内存                                      │
├──────────────────────────────────────────────────┤
│ ████ Pod1 3G                                      │
│ ██████ Pod2 5G                                    │
│ ██ Pod3 2G                                        │
│ ██████████ 你的Pod 9.5G                           │
│ ░░░░░░░░░░░░░░░░░░░░░░░░░░░ 空闲 12.5G            │
└──────────────────────────────────────────────────┘

调度器眼中的分配(Request视角):
┌──────────────────────────────────────────────────┐
│ 32GB 总容量                                       │
├──────────────────────────────────────────────────┤
│ ████ Pod1 Request 4G (实际只用3G,虚占1G)         │
│ ██████ Pod2 Request 6G (实际只用5G,虚占1G)       │
│ ████████ Pod3 Request 8G (实际只用2G,虚占6G) ← 严重虚占│
│ ████████ 你的Pod Request 8G (实际用9.5G,倒欠1.5G)│
├──────────────────────────────────────────────────┤
│ 已分配Request总和: 26G                            │
│ 剩余可调度: 6G                                     │
└──────────────────────────────────────────────────┘

关键:12.5G物理空闲 ≠ 6G可调度配额
差值 6.5G 就是碎片化浪费!

为什么会产生6.5G的碎片?

碎片来源1:Request高于实际使用(向上虚占)

Pod3: Request=8G, 实际=2G
虚占: 8G - 2G = 6G  ← 这6G物理内存是空闲的,但被"预留"了

碎片来源2:Request低于实际使用(向下透支)

你的Pod: Request=8G, 实际=9.5G  
透支: 9.5G - 8G = 1.5G  ← 这1.5G是"偷"了其他Pod预留的空间

净效应

# 正确计算
物理总内存: 32G
实际使用: 3+5+2+9.5 = 19.5G
物理空闲: 12.5G

Request总和: 4+6+8+8 = 26G
调度剩余配额: 32-26 = 6G

碎片化浪费 = 物理空闲 - 调度剩余配额 
           = 12.5G - 6G 
           = 6.5G

这6.5G物理内存明明空闲,但调度器认为已经用完了!

碎片化的后果

后果1:无法调度中等规格的Pod

# 现在有个新Pod需要 Request=8G(例如标准的Java微服务)
节点剩余调度配额: 6G  ← 不足8G,无法调度

# 但实际上物理内存空闲 12.5G,完全可以运行!
# 导致这个Pod必须调度到其他节点,增加跨节点通信成本

后果2:节点利用率低

# 节点实际利用率
实际使用: 19.5G / 32G = 61%

# 但调度器认为
Request占用: 26G / 32G = 81%  ← 看起来快满了

# 结果:节点看起来"满了",实际还很空闲
# 导致整个集群需要更多节点,增加云成本

后果3:触发不必要的Pod驱逐

# 当节点内存压力控制器(kubelet)检测到:
物理内存使用率 > 85% 时开始驱逐Pod

# 你的节点实际使用19.5G,使用率61%,完全安全
# 但因为你的Pod透支了1.5G,可能触发其他Pod被驱逐

# 例如:Pod3实际只用了2G,但K8s以为它需要8G
# 当节点内存紧张时,会按优先级驱逐Pod

如何避免碎片化?

原则1:Request应该接近实际使用

# 错误
resources:
  requests:
    memory: 8Gi    # 猜测值
  limits:
    memory: 16Gi

# 正确(基于监控数据)
resources:
  requests:
    memory: 10Gi   # 基于实际使用9.5G + 5%缓冲
  limits:
    memory: 12Gi   # 实际使用 + 20%缓冲

原则2:定期检查并调整

# 查看Pod实际内存使用(过去7天的P99)
kubectl exec -it pod-name -- cat /sys/fs/cgroup/memory/memory.usage_in_bytes

# 使用VPA自动调整(谨慎使用)
kubectl apply -f vpa.yaml

原则3:使用Guaranteed QoS

# Request = Limit 时,QoS为Guaranteed
# 这种Pod不会被驱逐,且调度更稳定
resources:
  requests:
    memory: 10Gi
  limits:
    memory: 10Gi   # 等于Request

总结一句话

调度资源碎片化:Pod的Request就像在节点上"画地为牢",即使物理内存空闲,但Request总量满了,新Pod就无法调度,导致明明有空地却无法建新房的尴尬局面。