1421 字
4 分钟
容量规划:保障系统稳定性的基石
某在线教育平台在开学季首日,用户量从平时的 10 万暴涨到 100 万,系统在 30 分钟内崩溃,恢复后又再次崩溃。事后复盘发现:没有做过容量规划,不知道系统极限在哪里,也没有限流和降级预案。容量规划的核心目标就是:在流量到来之前,知道系统能扛多少,扛不住时有预案。
一、容量规划的核心流程
graph TB
A[需求分析] --> B[性能测试]
B --> C[容量建模]
C --> D[资源规划]
D --> E[实施部署]
E --> F[监控调优]
F --> B
| 步骤 | 关键产出 |
|---|---|
| 需求分析 | QPS 目标、SLA 要求 |
| 性能测试 | 单实例性能基线 |
| 容量建模 | 实例数与 QPS 的关系 |
| 资源规划 | CPU、内存、磁盘、网络 |
| 监控调优 | 实际负载与预测的偏差 |
二、性能指标与测试
2.1 核心指标
| 指标 | 说明 | 目标值 |
|---|---|---|
| QPS | 每秒请求数 | 根据业务确定 |
| RT(Response Time) | 响应时间 | P99 < 200ms |
| 并发数 | 同时处理的请求数 | 根据线程数确定 |
| 错误率 | 失败请求比例 | < 0.1% |
| CPU 使用率 | 处理器利用率 | < 70% |
| 内存使用率 | 内存占用比例 | < 80% |
2.2 性能测试类型
| 类型 | 目的 | 方法 |
|---|---|---|
| 基准测试 | 确定单实例性能上限 | 逐步增加负载直到系统饱和 |
| 负载测试 | 验证系统在目标负载下的表现 | 持续施加目标 QPS |
| 压力测试 | 发现系统瓶颈和崩溃点 | 超过目标 QPS 持续施压 |
| 稳定性测试 | 验证长时间运行的稳定性 | 目标 QPS 持续 24-72 小时 |
2.3 性能测试结果分析
def analyze_results(results): sorted_results = sorted(results) n = len(sorted_results)
return { "qps": len(results) / duration, "avg": statistics.mean(results), "p50": sorted_results[int(n * 0.5)], "p90": sorted_results[int(n * 0.9)], "p99": sorted_results[int(n * 0.99)], "max": max(results), }三、扩展策略
3.1 垂直扩展(Scale Up)
增加单实例的资源(CPU、内存、磁盘):
| 优点 | 缺点 |
|---|---|
| 实现简单 | 有物理上限 |
| 改动小 | 成本非线性增长 |
| 无状态问题 | 单点故障风险 |
# Kubernetes VPA 配置apiVersion: autoscaling.k8s.io/v1kind: VerticalPodAutoscalermetadata: name: my-app-vpaspec: targetRef: apiVersion: apps/v1 kind: Deployment name: my-app updatePolicy: updateMode: "Auto"3.2 水平扩展(Scale Out)
增加实例数量:
| 优点 | 缺点 |
|---|---|
| 无理论上限 | 需要无状态设计 |
| 线性扩展 | 复杂度高 |
| 容错性好 | 运维成本增加 |
# Kubernetes HPA 配置apiVersion: autoscaling/v2kind: HorizontalPodAutoscalermetadata: name: my-app-hpaspec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: my-app minReplicas: 2 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 703.3 扩展策略选择
| 场景 | 推荐策略 | 原因 |
|---|---|---|
| 数据库 | 垂直扩展优先 | 水平扩展复杂(分库分表) |
| 无状态服务 | 水平扩展优先 | 简单、线性 |
| 有状态服务 | 垂直扩展优先 | 水平扩展需要状态迁移 |
| 缓存 | 垂直扩展优先 | 水平扩展影响命中率 |
四、限流与降级
4.1 限流
限流是保护系统的第一道防线,拒绝超出容量的请求:
class TokenBucket: def __init__(self, rate, capacity): self.rate = rate self.capacity = capacity self.tokens = capacity self.last_refill = time.time()
def allow_request(self, tokens=1): self._refill() if self.tokens >= tokens: self.tokens -= tokens return True return False
def _refill(self): now = time.time() elapsed = now - self.last_refill self.tokens = min(self.capacity, self.tokens + elapsed * self.rate) self.last_refill = now4.2 降级
降级是限流之后的第二道防线,用简化功能替代完整功能:
| 降级策略 | 说明 | 示例 |
|---|---|---|
| 功能降级 | 关闭非核心功能 | 评论区暂时关闭 |
| 数据降级 | 返回缓存或默认数据 | 推荐列表返回热门商品 |
| 体验降级 | 降低服务质量 | 图片改为缩略图 |
| 写降级 | 拒绝写操作,只保留读 | 暂停下单,允许浏览 |
class ServiceDegradation: def __init__(self): self.fallbacks = {} self.degradation_enabled = {}
def register_fallback(self, func_name, fallback_func): self.fallbacks[func_name] = fallback_func
def execute(self, func_name, *args, **kwargs): if self.degradation_enabled.get(func_name): return self.fallbacks[func_name](*args, **kwargs) try: return self.execute_original(func_name, *args, **kwargs) except Exception: if func_name in self.fallbacks: return self.fallbacks[func_name](*args, **kwargs) raise4.3 熔断
熔断器在服务故障时自动切断调用链:
正常 → 失败率超过阈值 → 熔断(快速失败) ↓ 超时后探测 → 成功 → 恢复 ↓ 失败 → 继续熔断五、缓存策略
5.1 多级缓存
graph TB
A[本地缓存] --> B[分布式缓存]
B --> C[数据库]
| 层级 | 技术 | 延迟 | 容量 |
|---|---|---|---|
| L1 本地缓存 | Caffeine/Guava | <1ms | 有限 |
| L2 分布式缓存 | Redis Cluster | 1-5ms | 大 |
| L3 数据库 | MySQL/PostgreSQL | 10-100ms | 最大 |
5.2 缓存策略选择
| 策略 | 适用场景 | 说明 |
|---|---|---|
| Cache Aside | 通用场景 | 先查缓存,未命中则查数据库并回写 |
| Read Through | 读多写少 | 缓存层自动从数据库加载 |
| Write Through | 写多读少 | 写入时同步更新缓存和数据库 |
| Write Behind | 写密集 | 先写缓存,异步批量写入数据库 |
5.3 TTL 配置
| 数据类型 | TTL | 原因 |
|---|---|---|
| 热点数据 | 5 分钟 | 变化频繁,需要及时更新 |
| 用户数据 | 1 小时 | 变化较慢 |
| 配置数据 | 1 天 | 几乎不变 |
六、容量计算模型
6.1 线性模型
假设 QPS 与实例数成正比:
所需实例数 = 目标 QPS / 单实例 QPS所需 CPU = 单实例 CPU * 实例数所需内存 = 单实例内存 * 实例数示例:
单实例基线:QPS=500, CPU=2核, 内存=4GB目标 QPS:5000所需实例数:5000 / 500 = 10所需 CPU:2 * 10 = 20 核所需内存:4 * 10 = 40 GB6.2 非线性模型
实际系统中,扩展效率受串行部分限制(Amdahl 定律):
加速比 = 1 / (串行比例 + 并行比例 / 实例数)如果 10% 的操作是串行的:
2 实例:加速比 = 1 / (0.1 + 0.9/2) = 1.824 实例:加速比 = 1 / (0.1 + 0.9/4) = 3.088 实例:加速比 = 1 / (0.1 + 0.9/8) = 4.71无限实例:加速比 = 1 / 0.1 = 10(上限)6.3 安全裕度
容量规划需要预留安全裕度:
规划容量 = 预测峰值 * (1 + 安全裕度)安全裕度建议:20-30%| 考虑因素 | 裕度 |
|---|---|
| 突发流量 | 20% |
| 性能衰减 | 10% |
| 故障容错 | 20% |
| 总裕度 | 30-50% |
七、容量规划实践
7.1 容量规划清单
- 确定业务峰值 QPS 和 SLA
- 进行基准测试,获取单实例性能基线
- 根据线性/非线性模型计算所需实例数
- 预留 30% 安全裕度
- 配置 HPA/VPA 自动扩缩容
- 设置限流阈值和降级预案
- 部署监控告警,持续观察
7.2 监控告警
| 指标 | 告警阈值 | 动作 |
|---|---|---|
| CPU 使用率 | > 70% | 扩容 |
| 内存使用率 | > 80% | 扩容 |
| QPS 接近限流阈值 | > 80% | 启动降级 |
| 错误率 | > 1% | 熔断 |
| P99 延迟 | > 500ms | 排查瓶颈 |
7.3 降级预案
为每个核心业务准备降级预案:
| 业务 | 正常模式 | 降级模式 |
|---|---|---|
| 下单 | 全流程 | 只浏览不下单 |
| 搜索 | 完整索引 | 热门搜索词缓存 |
| 推荐 | 实时计算 | 预计算热门列表 |
| 评论 | 实时展示 | 关闭评论 |
容量规划不是一次性的工作,而是持续的过程。定期进行性能测试更新基线,监控实际负载与预测的偏差,及时调整资源配置和限流阈值。科学的容量规划加上完善的限流降级预案,才能让系统在流量洪峰面前从容应对。
支持与分享
如果这篇文章对你有帮助,欢迎支持作者或分享给更多人
部分信息可能已经过时
相关文章 智能推荐
1
分布式追踪:定位跨服务性能瓶颈
分布式系统深入 深入解析分布式追踪——OpenTelemetry 标准、Span 与 Trace 模型、采样策略与 Jaeger 工程实践
2
CAP 定理:分布式系统的不可能三角
分布式系统深入 深入理解 CAP 定理——一致性、可用性与分区容错性为何不可兼得,以及工程实践中的取舍策略
3
Paxos 协议:分布式共识的理论基石
分布式系统深入 深入理解 Paxos 协议——Basic Paxos 与 Multi-Paxos 的原理、推导过程与工程挑战
4
分布式系统系列导读
分布式系统深入 分布式系统系列文章导读——从共识算法到服务网格,系统梳理分布式核心知识体系
5
API 网关:微服务的统一入口
分布式系统深入 深入解析 API 网关——限流算法、熔断器模式、灰度发布与服务发现集成的工程实践






