K8s资源调度为什么直接影响业务稳定性
Kubernetes集群里,Pod调度失败、OOMKilled、CPU Throttling是最常见的三类资源问题。根本原因几乎都是Requests和Limits配置不当——要么设太低导致Pod被频繁驱逐,要么设太高造成资源浪费和调度热点。把Requests/Limits当随便填的数字,线上迟早出事。
Requests与Limits的核心机制
Requests是调度器调度的依据——Scheduler保证Pod被分配到有足够资源的Node上。Limits是运行时的硬上限——超过CPU Limit会被Throttle,超过Memory Limit会触发OOMKilled。
# Pod资源声明示例
resources:
requests:
cpu: "500m" # 调度保障:至少0.5核
memory: "256Mi" # 调度保障:至少256MB
limits:
cpu: "1000m" # 运行上限:最多1核
memory: "512Mi" # 运行上限:最多512MB
CPU是可压缩资源,超限会被Throttle但不会杀进程;Memory是不可压缩资源,超限直接OOMKilled。这个区别决定了CPU Limits可以设得相对宽松,Memory Limits必须严格对齐实际用量。
资源配置的实战方法论
不要凭感觉设Requests/Limits。用数据说话:
第一步:无限制压测,采集真实用量
先不设Limits跑一段时间,用Prometheus采集CPU和Memory的P99用量:
# Prometheus查询P99内存用量
quantile_over_time(0.99, container_memory_working_set_bytes{container!="POD",namespace="prod"}[7d])
# P99 CPU用量
quantile_over_time(0.99, rate(container_cpu_usage_seconds_total{container!="POD",namespace="prod"}[5m])[7d])
第二步:按公式计算配置值
- Requests.memory = P99用量 x 1.2(留20%缓冲)
- Limits.memory = P99用量 x 1.5(留50%弹性空间)
- Requests.cpu = P99用量 x 1.1
- Limits.cpu = P99用量 x 2.0
Java应用需要特殊处理,JVM堆内存远低于容器Memory Limits时才能避免OOM。经验值:容器Memory Limits = JVM Xmx x 1.5,因为堆外内存(Metaspace、线程栈、NIO Direct Buffer)也要算进来。
第三步:设置LimitRange和ResourceQuota作为兜底
# LimitRange - 命名空间级默认值和上下限
apiVersion: v1
kind: LimitRange
metadata:
name: prod-limits
namespace: prod
spec:
limits:
- type: Container
default:
cpu: "500m"
memory: "256Mi"
defaultRequest:
cpu: "100m"
memory: "128Mi"
max:
cpu: "4"
memory: "8Gi"
min:
cpu: "50m"
memory: "64Mi"
---
# ResourceQuota - 命名空间总资源限制
apiVersion: v1
kind: ResourceQuota
metadata:
name: prod-quota
namespace: prod
spec:
hard:
requests.cpu: "20"
requests.memory: "40Gi"
limits.cpu: "40"
limits.memory: "80Gi"
pods: "100"
HPA自动伸缩:从指标配置到冷启动优化
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: api-server-hpa
namespace: prod
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: api-server
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
behavior:
scaleUp:
stabilizationWindowSeconds: 30
policies:
- type: Percent
value: 50
periodSeconds: 60
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Pods
value: 1
periodSeconds: 120
HPA配置的关键坑点:
1. 扩容速度跟不上流量突增 — 默认每60秒检查一次指标,流量洪峰来时来不及。解法:配合PodDisruptionBudget和预热Pod池,或在业务层做限流兜底。
2. 扩容后新Pod冷启动慢 — Java应用启动要30-60秒。解法:开启Readiness Gate,确保Pod就绪后才接收流量;同时用--horizontal-pod-autoscaler-initial-readiness-delay调整就绪判定延迟。
3. 缩容震荡 — CPU波动导致反复扩缩。解法:stabilizationWindowSeconds设5分钟以上,缩容策略设type: Pods, value: 1,一次最多缩一个。
Node级资源压力防护:eviction与descheduler
当Node内存或磁盘压力过高,Kubelet会主动驱逐Pod。但驱逐顺序由QoS等级决定:
- Guaranteed(Requests = Limits):最后被驱逐
- Burstable(Requests < Limits):中间优先级
- BestEffort(无Requests/Limits):最先被驱逐
生产环境核心业务必须设Guaranteed QoS,避免被无辜驱逐。
集群长期运行后,部分Node资源碎片化严重,Pod调度不均衡。部署descheduler定期重平衡:
apiVersion: "descheduler/v1alpha1"
kind: "DeschedulerPolicy"
strategies:
"RemoveDuplicates":
enabled: true
"LowNodeUtilization":
enabled: true
params:
nodeResourceUtilizationThresholds:
thresholds:
cpu: 20
memory: 20
pods: 20
targetThresholds:
cpu: 50
memory: 50
pods: 50
资源调度是K8s运维的地基。Requests/Limits配不好,HPA调优就是空中楼阁。先用量化数据定好每类工作负载的资源基线,再用LimitRange/ResourceQuota兜底,最后才是HPA和集群重平衡。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/kubernetes-rong-qi-bian-pai-zi-yuan-diao-du-shi-zhan/