第七部分:Kubernetes 生产级调优案例
真实场景下的系统化调优实践
目录
案例1:高并发 API 集群调优
场景描述
业务背景:
- 电商平台 API 服务
- 日常流量:5k QPS
- 峰值流量:15k QPS(促销活动)
- 服务:Go 语言编写,响应时间要求 < 100ms
初始问题:
- 高峰期 P99 延迟达到 500ms
- CPU 使用率波动大
- 部分请求超时
- 内存使用持续增长
调优过程
第1步:性能瓶颈定位
#!/bin/bash
# 性能瓶颈定位脚本
echo "=== 性能瓶颈定位 ==="
# 1. 查看 Pod 资源使用
kubectl top pod -l app=api-service
kubectl describe pod -l app=api-service
# 2. 查看节点资源使用
kubectl top node
# 3. 查看应用日志
kubectl logs -l app=api-service --tail=100
# 4. 查看 Prometheus 指标
kubectl port-forward -n monitoring svc/prometheus 9090:9090 &
echo "查看指标: http://localhost:9090"
发现问题:
- CPU throttling 严重(throttled_time 占比 40%)
- 内存缓慢泄漏(每小时增长 100MB)
- 部分 Pod 负载不均
第2步:CPU 调优
原始配置:
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: 1000m
memory: 1Gi
调优后配置:
resources:
requests:
cpu: 1000m
memory: 512Mi
# 移除 CPU limits,避免 throttling
测试脚本:
#!/bin/bash
# CPU 调优效果测试
# 部署优化后的配置
kubectl apply -f api-service-optimized.yaml
# 等待 Pod 就绪
kubectl wait --for=condition=Ready pod -l app=api-service --timeout=60s
# 压力测试
wrk -t12 -c400 -d60s --latency http://api-service/api/products
# 监控 CPU 使用
kubectl top pod -l app=api-service
效果:
- P99 延迟:500ms → 120ms
- CPU throttling:40% → 0%
第3步:内存泄漏修复
#!/bin/bash
# 内存泄漏分析
# 1. 启用 pprof
kubectl port-forward -n default svc/api-service 6060:6060 &
# 2. 收集内存 profile
curl http://localhost:6060/debug/pprof/heap > heap.prof
# 3. 分析内存使用
go tool pprof -http=:8080 heap.prof
# 4. 生成火焰图
go tool pprof -png heap.prof > memory-flamegraph.png
发现问题:
- HTTP 连接池未正确关闭
- 缓存未设置过期时间
修复代码:
// 修复前
client := &http.Client{}
// 修复后
client := &http.Client{
Transport: &http.Transport{
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 90 * time.Second,
},
Timeout: 10 * time.Second,
}
// 缓存添加过期时间
cache := cache.New(5*time.Minute, 10*time.Minute)
效果:
- 内存增长率:100MB/h → 稳定在 512MB
第4步:负载均衡优化
# 启用 Pod 反亲和
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-service
spec:
replicas: 12
template:
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- api-service
topologyKey: kubernetes.io/hostname
效果:
- Pod 分布更均匀
- 节点负载更平衡
最终结果
| 指标 | 优化前 | 优化后 | 提升 |
|---|---|---|---|
| P99 延迟 | 500ms | 80ms | 84% ↓ |
| P50 延迟 | 100ms | 30ms | 70% ↓ |
| QPS 承载 | 5k | 20k | 300% ↑ |
| CPU 使用率 | 85% (throttling) | 65% (稳定) | - |
| 内存使用 | 不稳定 | 稳定 | - |
| 成本 | 基准 | +20% | 性价比提升 |
案例2:AI 推理服务优化
场景描述
业务背景:
- 图像识别推理服务
- 模型:ResNet-50
- 输入:批量图片(batch size: 32)
- GPU:NVIDIA T4
初始问题:
- GPU 利用率仅 40%
- 推理吞吐量:200 images/s(预期:800+ images/s)
- 模型加载时间长(30s)
调优过程
第1步:GPU 调度配置
apiVersion: v1
kind: Pod
metadata:
name: ai-inference
spec:
containers:
- name: inference
image: pytorch/pytorch:1.13.0-cuda11.6-cudnn8-runtime
resources:
limits:
nvidia.com/gpu: 1
requests:
cpu: 4
memory: 8Gi
volumeMounts:
- name: model-storage
mountPath: /models
volumes:
- name: model-storage
persistentVolumeClaim:
claimName: model-pvc
nodeSelector:
accelerator: nvidia-t4
第2步:模型加载优化
问题:每次 Pod 重启都需要重新下载模型
解决方案:使用 PVC 缓存模型
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: model-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: fast-ssd
resources:
requests:
storage: 50Gi
模型预加载脚本:
#!/usr/bin/env python3
import torch
import torchvision
import os
MODEL_PATH = "/models/resnet50.pth"
def preload_model():
if os.path.exists(MODEL_PATH):
print(f"Loading model from cache: {MODEL_PATH}")
model = torch.load(MODEL_PATH)
else:
print("Downloading model...")
model = torchvision.models.resnet50(pretrained=True)
torch.save(model, MODEL_PATH)
print(f"Model cached at: {MODEL_PATH}")
model.eval()
model.cuda()
return model
if __name__ == "__main__":
model = preload_model()
print("Model ready for inference")
效果:
- 模型加载时间:30s → 2s
第3步:批处理优化
#!/usr/bin/env python3
import torch
from torch.utils.data import DataLoader
import time
class InferenceBatchProcessor:
def __init__(self, model, batch_size=32):
self.model = model
self.batch_size = batch_size
self.device = torch.device("cuda")
def process_batch(self, images):
# 确保输入在 GPU 上
images = images.to(self.device, non_blocking=True)
# 使用 torch.no_grad() 节省内存
with torch.no_grad():
outputs = self.model(images)
return outputs.cpu()
def benchmark(self, num_batches=100):
dummy_input = torch.randn(
self.batch_size, 3, 224, 224
).to(self.device)
# 预热
for _ in range(10):
self.process_batch(dummy_input)
torch.cuda.synchronize()
start = time.time()
for _ in range(num_batches):
self.process_batch(dummy_input)
torch.cuda.synchronize()
end = time.time()
total_images = num_batches * self.batch_size
throughput = total_images / (end - start)
print(f"Throughput: {throughput:.2f} images/s")
print(f"Latency: {(end - start) / num_batches * 1000:.2f} ms/batch")
return throughput
# 使用示例
model = preload_model()
processor = InferenceBatchProcessor(model, batch_size=32)
processor.benchmark()
第4步:混合精度推理
#!/usr/bin/env python3
import torch
# 启用混合精度
model = model.half() # FP16
# 或使用 TorchScript 优化
model_scripted = torch.jit.script(model)
model_scripted.save("model_scripted.pt")
效果:
- 推理速度提升:200 images/s → 850 images/s
- GPU 利用率:40% → 85%
- 内存使用:8GB → 4GB
最终结果
| 指标 | 优化前 | 优化后 | 提升 |
|---|---|---|---|
| 吞吐量 | 200 img/s | 850 img/s | 325% ↑ |
| 延迟 | 160ms | 38ms | 76% ↓ |
| GPU 利用率 | 40% | 85% | 113% ↑ |
| 模型加载 | 30s | 2s | 93% ↓ |
| 内存使用 | 8GB | 4GB | 50% ↓ |
案例3:数据库集群高可用
场景描述
业务背景:
- MySQL 主从集群
- 数据量:500GB
- 读写比:7:3
- 要求:RPO < 1分钟,RTO < 5分钟
初始问题:
- 主库故障后手动切换,RTO > 30分钟
- 从库延迟时有发生
- 备份恢复测试不完善
调优过程
第1步:StatefulSet 部署
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: mysql
replicas: 3
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: password
volumeMounts:
- name: data
mountPath: /var/lib/mysql
- name: config
mountPath: /etc/mysql/conf.d
resources:
requests:
cpu: 2
memory: 4Gi
limits:
cpu: 4
memory: 8Gi
volumes:
- name: config
configMap:
name: mysql-config
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: fast-ssd
resources:
requests:
storage: 100Gi
第2步:主从复制配置
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql-config
data:
master.cnf: |
[mysqld]
server-id=1
log-bin=mysql-bin
binlog_format=ROW
gtid_mode=ON
enforce_gtid_consistency=ON
max_connections=1000
innodb_buffer_pool_size=4G
innodb_flush_log_at_trx_commit=2
sync_binlog=1
slave.cnf: |
[mysqld]
server-id=2
relay-log=relay-bin
read_only=ON
gtid_mode=ON
enforce_gtid_consistency=ON
max_connections=1000
innodb_buffer_pool_size=4G
第3步:自动故障切换
使用 MySQL Operator 实现自动故障切换:
#!/bin/bash
# 安装 MySQL Operator
# 1. 添加 Helm 仓库
helm repo add mysql-operator https://mysql.github.io/mysql-operator/
helm repo update
# 2. 安装 Operator
helm install mysql-operator mysql-operator/mysql-operator \
--namespace mysql-operator \
--create-namespace
# 3. 部署 MySQL 集群
kubectl apply -f - <<EOF
apiVersion: mysql.oracle.com/v2
kind: InnoDBCluster
metadata:
name: mysql-cluster
spec:
secretName: mysql-secret
tlsUseSelfSigned: true
instances: 3
router:
instances: 2
datadirVolumeClaimTemplate:
accessModes:
- ReadWriteOnce
storageClassName: fast-ssd
resources:
requests:
storage: 100Gi
podSpec:
resources:
requests:
cpu: 2
memory: 4Gi
limits:
cpu: 4
memory: 8Gi
EOF
第4步:备份恢复方案
#!/bin/bash
# MySQL 自动备份脚本
# 1. 创建备份 CronJob
kubectl apply -f - <<EOF
apiVersion: batch/v1
kind: CronJob
metadata:
name: mysql-backup
spec:
schedule: "0 2 * * *" # 每天凌晨2点
jobTemplate:
spec:
template:
spec:
containers:
- name: backup
image: mysql:8.0
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: password
command:
- /bin/sh
- -c
- |
mysqldump -h mysql-0.mysql \
-u root -p\$MYSQL_ROOT_PASSWORD \
--all-databases --single-transaction \
--master-data=2 --flush-logs \
| gzip > /backup/mysql-\$(date +%Y%m%d-%H%M%S).sql.gz
volumeMounts:
- name: backup
mountPath: /backup
volumes:
- name: backup
persistentVolumeClaim:
claimName: mysql-backup-pvc
restartPolicy: OnFailure
EOF
# 2. 创建备份存储
kubectl apply -f - <<EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-backup-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: standard
resources:
requests:
storage: 500Gi
EOF
第5步:性能优化
-- MySQL 性能优化配置
-- 1. 调整缓冲池大小
SET GLOBAL innodb_buffer_pool_size = 4294967296; -- 4GB
-- 2. 优化查询缓存
SET GLOBAL query_cache_size = 67108864; -- 64MB
SET GLOBAL query_cache_type = 1;
-- 3. 调整连接数
SET GLOBAL max_connections = 1000;
-- 4. 优化慢查询日志
SET GLOBAL slow_query_log = 1;
SET GLOBAL long_query_time = 2;
SET GLOBAL log_queries_not_using_indexes = 1;
-- 5. 创建必要的索引
ANALYZE TABLE orders;
OPTIMIZE TABLE products;
最终结果
| 指标 | 优化前 | 优化后 | 提升 |
|---|---|---|---|
| RTO | 30分钟 | 3分钟 | 90% ↓ |
| RPO | 5分钟 | 30秒 | 90% ↓ |
| 查询性能 | 基准 | +40% | - |
| 故障切换 | 手动 | 自动 | - |
| 备份频率 | 每周 | 每天 | - |
案例4:混合负载调度优化
场景描述
业务背景:
- 集群同时运行:
- Web 服务(CPU 密集)
- 数据处理任务(I/O 密集)
- 机器学习训练(GPU 密集)
- 批处理作业(内存密集)
初始问题:
- 资源利用率不均
- 批处理作业影响在线服务
- GPU 资源浪费
调优过程
第1步:节点分类
#!/bin/bash
# 节点分类标签
# CPU 密集型节点
kubectl label nodes node-1 workload-type=cpu-intensive
kubectl label nodes node-2 workload-type=cpu-intensive
# I/O 密集型节点(配置 SSD)
kubectl label nodes node-3 workload-type=io-intensive
kubectl label nodes node-4 workload-type=io-intensive
# GPU 节点
kubectl label nodes node-5 workload-type=gpu-intensive
kubectl label nodes node-6 workload-type=gpu-intensive
第2步:工作负载分类部署
# Web 服务(CPU 密集)
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-service
spec:
replicas: 6
template:
spec:
nodeSelector:
workload-type: cpu-intensive
containers:
- name: web
image: web:latest
resources:
requests:
cpu: 2
memory: 2Gi
limits:
memory: 4Gi
priorityClassName: high-priority
---
# 数据处理任务(I/O 密集)
apiVersion: apps/v1
kind: Deployment
metadata:
name: data-processor
spec:
replicas: 4
template:
spec:
nodeSelector:
workload-type: io-intensive
containers:
- name: processor
image: processor:latest
resources:
requests:
cpu: 1
memory: 4Gi
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
persistentVolumeClaim:
claimName: fast-storage-pvc
priorityClassName: medium-priority
---
# 机器学习训练(GPU 密集)
apiVersion: batch/v1
kind: Job
metadata:
name: ml-training
spec:
template:
spec:
nodeSelector:
workload-type: gpu-intensive
containers:
- name: training
image: pytorch:latest
resources:
limits:
nvidia.com/gpu: 1
cpu: 4
memory: 16Gi
priorityClassName: low-priority
restartPolicy: OnFailure
第3步:优先级和抢占配置
# 高优先级(在线服务)
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: high-priority
value: 1000000
globalDefault: false
description: "高优先级在线服务"
---
# 中优先级(数据处理)
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: medium-priority
value: 100000
globalDefault: false
description: "中优先级数据处理"
---
# 低优先级(批处理)
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: low-priority
value: 1000
globalDefault: false
description: "低优先级批处理任务"
第4步:资源配额管理
# Web 服务资源配额
apiVersion: v1
kind: ResourceQuota
metadata:
name: web-quota
namespace: web
spec:
hard:
requests.cpu: "20"
requests.memory: 40Gi
limits.memory: 80Gi
pods: "30"
---
# 批处理资源配额
apiVersion: v1
kind: ResourceQuota
metadata:
name: batch-quota
namespace: batch
spec:
hard:
requests.cpu: "10"
requests.memory: 40Gi
nvidia.com/gpu: "4"
pods: "20"
最终结果
| 指标 | 优化前 | 优化后 | 提升 |
|---|---|---|---|
| CPU 利用率 | 45% | 75% | 67% ↑ |
| GPU 利用率 | 30% | 80% | 167% ↑ |
| 在线服务稳定性 | 不稳定 | 稳定 | - |
| 批处理完成时间 | 基准 | +15% | 可接受 |
| 资源成本 | 基准 | -25% | - |
总结与最佳实践
性能调优黄金法则
| 维度 | 最佳实践 | 避免 |
|---|---|---|
| CPU | 移除 limits,只设置 requests | 过度限制导致 throttling |
| 内存 | requests = limits | 内存泄漏导致 OOM |
| 存储 | 使用 SSD + 合适的 StorageClass | OverlayFS 层数过多 |
| 网络 | 统一 MTU,优化 DNS | 默认配置 |
| 调度 | 使用亲和性/反亲和性 | 所有 Pod 堆在一起 |
监控指标体系
# 关键监控指标
监控维度:
应用层:
- 请求延迟 (P50/P95/P99)
- 错误率
- QPS/TPS
容器层:
- CPU 使用率
- 内存使用率
- CPU throttling
- OOM 次数
节点层:
- 负载均衡
- 磁盘 I/O
- 网络吞吐
集群层:
- Pod 调度延迟
- API Server 响应时间
- etcd 性能
调优流程模板
1. 问题识别
└─ 监控告警 / 用户反馈
2. 数据收集
├─ 应用日志
├─ 系统指标
└─ 性能 profile
3. 瓶颈定位
├─ CPU / 内存 / I/O / 网络
└─ 应用代码 / 配置 / 架构
4. 制定方案
├─ 资源调整
├─ 代码优化
└─ 架构改进
5. 实施验证
├─ 灰度发布
├─ A/B 测试
└─ 性能对比
6. 总结归档
├─ 文档记录
├─ 经验沉淀
└─ 监控完善
完成! 通过这些真实案例,你已经掌握了 Kubernetes 生产环境的系统化调优方法。
下一部分:命令速查与YAML模板库