---
title: 高性能分布式系统设计
type: concept
domain: system-design
tags: [system-design, high-performance, distributed, sla, qps, p99, c4, architecture]
status: learning
created: 2026-09-27
last_reviewed: 2026-09-27
method: c4
related_questions:
  - "如何设计一个高性能的分布式系统"
related_knowledge:
  - ../microservice/microservice-architecture.md
  - ../microservice/resilience-patterns.md
  - ../redis/cache-three-failures.md
  - ../mysql/mysql-index-design.md
anki_cards: 7
interview_rounds:
  - "2026-09-27-round-1-Q9"
  - "2026-10-08-round-1"
last_reviewed: 2026-10-08
---

# 高性能分布式系统设计

> 高性能设计的**第一步是量化目标**（80% 的回答都缺这步）：QPS、P99 延迟、可用性 SLO、错误率。有了目标才能推导架构和选型。

## TL;DR（30 秒扫完）

- **量化先行**：QPS（如 10 万）、P99 延迟（如 100ms）、可用性（如 99.99%）、错误率（如 <0.1%）
- **架构分层**（自上而下）：CDN+DDoS 防护 → 网关 → 负载均衡 → 业务层 → 缓存层 → 数据层 → 异步层
- **各层优化**：协议（HTTP/2/Protobuf）+ 缓存（多级）+ 数据库（分库分表/读写分离）+ 异步（MQ 削峰）+ 线程模型
- **韧性 + 可观测**：限流/熔断/降级 + Prometheus/SkyWalking/ELK

## 关键结论

- **结论 A**：高性能设计**第一步是量化目标**，没给 SLA 的数字就是空谈
- **结论 B**：架构分层是"CDN → 网关 → LB → 业务 → 缓存 → 数据 → 异步"，自上而下
- **结论 C**：写路径优化和读路径优化都要讲（分库分表/批量写/异步写/CQRS）
- **结论 D**：可观测性（Metrics/Tracing/Logging）是必需的，否则不知道哪里出问题

## 完整讲解（费曼四步）

### STEP 1 · 概念

高性能分布式系统是通过分层架构、协议优化、缓存、异步、数据分片等手段，让系统在量化 SLA（QPS/P99/可用性）约束下满足业务需求。

### STEP 2 · 大白话

**类比快递网络**：
- CDN = 全国仓库（就近取货）
- 网关 = 分拨中心（限流、鉴权）
- 负载均衡 = 快递员调度（分单）
- 缓存 = 常用件预置（快取）
- 数据库 = 总仓（最终存储）
- MQ = 排队通道（削峰）

### STEP 3 · 底层

**STEP 1：量化目标（80% 候选人缺这步）**

| 指标 | 目标示例 | 说明 |
|------|---------|------|
| QPS/TPS | 10 万 QPS | 每秒查询/事务数 |
| P99 延迟 | <100ms | 99% 请求的响应时间 |
| 可用性 | 99.99% | 允许 4.3 分钟/年不可用 |
| 错误率 | <0.1% | 5xx 或业务错误比例 |
| RPO | <1 秒 | 最多丢失 1 秒数据 |
| RTO | <30 秒 | 故障恢复时间 |

有了目标才能推导：机器数 = QPS / 单机 QPS × 1.25（余量）

**STEP 2：架构分层（自上而下）**

```
1. 接入层：CDN（静态加速）+ DDoS 防护（Cloudflare/高防 IP）
2. 网关层：Nginx/APISIX/Spring Cloud Gateway（限流/鉴权/路由）
3. 负载均衡层：L4（LVS）+ L7（Nginx）+ 客户端 LB
4. 业务层：无状态微服务，水平扩展
5. 缓存层：多级缓存（Caffeine 本地 + Redis 分布式）
6. 数据层：MySQL 分库分表 + ES（搜索）+ HBase（冷数据）
7. 异步层：Kafka/RocketMQ 削峰、事件驱动
```

**STEP 3：各层优化手段**

**网络接入层**：
- CDN：静态资源全球加速
- DDoS 防护：Cloudflare、高防 IP
- 网关：Nginx/APISIX/Spring Cloud Gateway（限流、鉴权、路由）

**负载均衡层**：
- L4（LVS）+ L7（Nginx）+ 客户端 LB（Ribbon/LoadBalancer）
- 一致性哈希、会话保持

**协议与序列化**：
- HTTP/2 多路复用（避免队头阻塞）
- gRPC（HTTP/2 + Protobuf）
- Protobuf 比 JSON 小 3-10 倍
- TCP 长连接、HTTP keep-alive
- gzip/zstd 压缩

**缓存层**：
- 多级缓存：本地（Caffeine）→ 分布式（Redis Cluster）→ 数据库
- 缓存穿透：布隆过滤器
- 缓存击穿：互斥锁
- 缓存雪崩：随机 TTL

**数据层**：
- 读写分离、分库分表、CQRS
- 连接池（HikariCP）、慢查询监控、批量操作
- 冷热数据分离（ES/HBase 存冷数据）

**异步与削峰**：
- MQ（Kafka/RocketMQ）吸收流量峰值
- 事件驱动、最终一致性
- 先写 MQ 再异步落库

**线程模型**：
- Netty Reactor（Boss + Worker）
- 虚拟线程（JDK21）应对高并发 IO
- 线程池隔离（避免共享池打满）

**STEP 4：韧性 + 可观测性**

**韧性设计**：
- 限流（Sentinel 令牌桶）
- 熔断（Hystrix/Sentinel）
- 降级（兜底值）
- 超时/重试/幂等

**可观测性三大支柱**：
- **Metrics**：Prometheus（指标）+ Grafana（可视化）
- **Tracing**：SkyWalking/Jaeger/OpenTelemetry（链路追踪）
- **Logging**：ELK（Elasticsearch + Logstash + Kibana）

**STEP 5：举例（秒杀场景）**

用户下单峰值 10 万 QPS：
1. CDN + Nginx 限流（按 QPS 8 万）
2. 网关做黑名单过滤
3. Kafka 削峰（后端按 1000 QPS 消费落库）
4. Redis 库存预扣（Lua 原子操作）
5. 订单 MQ 异步持久化
6. 结果异步通知用户

**P99 延迟 <200ms**

### STEP 4 · 简化

> **口诀**：先量化（QPS/P99/SLO）→ 再分层（CDN/网关/LB/业务/缓存/数据/异步）→ 各层优化 → 韧性 + 可观测。没数字就是空谈。

## 常见误区（从面试记录提炼）

- **误区 1（最严重）**：完全没给量化指标→ 正确：QPS、P99 延迟、可用性、错误率——一个数字都不给就是空谈架构
- **误区 2**：只讲读路径，写路径缺席→ 正确：写路径（分库分表/批量写/异步写/CQRS）同样重要
- **误区 3**：数据库层优化缺席→ 正确：连接池、慢查询、批量、读写分离、分库分表——这是"高性能"的重灾区
- **误区 4**：协议层优化缺席→ 正确：HTTP/2 多路复用、Protobuf、压缩——能提性能 3-10 倍
- **误区 5**："过滤异常请求"没具体说→ 正确：是限流？鉴权？参数校验？WAF？必须说清楚

## 延伸追问（面试追问预演）

1. **你说 P99 目标 100ms，如何验证？**
   - 要点：压测工具（JMeter/AB），指标采集（SkyWalking APM），看 P50/P95/P99 分布；容量规划（单机 QPS × 80% × 机器数 = 系统 QPS）。
2. **多级缓存如何保证一致性？**
   - 要点：Cache-Aside 模式（先查缓存，未命中查库并回写）；更新时"先更库再删缓存"；延迟双删；Redis 发布订阅通知本地缓存失效。
3. **数据库是瓶颈时怎么办？**
   - 要点：先看慢查询（SHOW SLOW QUERIES）、加索引、读写分离、分库分表、热点数据缓存、离线任务（ETL 到 ES/HBase）、异步写入（先写 MQ 再异步落库）。
4. **虚拟线程能解决所有高并发问题吗？**
   - 要点：虚拟线程对 IO 密集型有效，CPU 密集型无效（还是受限于 CPU 核数）；需要 JDK21+；对 synchronized 有 pinning 问题，建议用 ReentrantLock。

## 速查表

```
STEP 1：量化目标（QPS 10 万 / P99 100ms / 可用性 99.99% / 错误率 <0.1%）
STEP 2：架构分层（CDN → 网关 → LB → 业务 → 缓存 → 数据 → 异步）
STEP 3：各层优化（协议/缓存/数据库/异步/线程模型）
STEP 4：韧性（限流/熔断/降级/超时/重试/幂等）+ 可观测（Metrics/Tracing/Logging）
秒杀举例：CDN+Nginx 限流 → 网关过滤 → Kafka 削峰 → Redis 预扣 → 异步持久化
关键：没数字就是空谈；写路径和读路径都要讲；协议/缓存/DB 三层缺一不可
```

## 关联题目（题库）

- [x] 《如何设计一个高性能的分布式系统》—— 2026-09-27 Round 1 Q9, 评分 ⭐⭐⭐

## 关联知识

- [微服务架构演进与特征](../microservice/microservice-architecture.md)
- [限流降级熔断](../microservice/resilience-patterns.md)
- [缓存三失效](../redis/cache-three-failures.md)
- [MySQL 索引设计](../mysql/mysql-index-design.md)

## Anki 候选卡片

1. **正**：高性能分布式系统设计第一步是什么？**反**：量化目标（QPS/P99/可用性/错误率）——没数字就是空谈
2. **正**：架构分层 7 层（自上而下）？**反**：CDN+DDoS 防护 → 网关 → 负载均衡 → 业务层 → 缓存层 → 数据层 → 异步层
3. **正**：各层优化手段（协议/缓存/DB/异步/线程）？**反**：HTTP/2+Protobuf（协议）/ 多级缓存（本地+分布式）/ 分库分表+读写分离（DB）/ MQ 削峰（异步）/ Netty Reactor+虚拟线程（线程模型）
4. **正**：写路径优化和读路径优化？**反**：读路径（缓存+索引）；写路径（分库分表/批量写/异步写/CQRS）
5. **正**：可观测性三大支柱？**反**：Metrics（Prometheus+Grafana）/ Tracing（SkyWalking/Jaeger/OpenTelemetry）/ Logging（ELK）
6. **正**：多级缓存如何保证一致性？**反**：Cache-Aside 先查缓存未命中查库回写；更新时"先更库再删缓存"；延迟双删；Redis 发布订阅通知本地缓存失效
7. **正**：秒杀场景的性能优化举例？**反**：CDN+Nginx 限流 → 网关过滤 → Kafka 削峰（后端 1000 QPS 消费）→ Redis 库存预扣（Lua 原子）→ 订单 MQ 异步持久化；P99 <200ms

---

## 2026-10-08 追加：容量规划黄金公式 + 性能优化五步法

> 本次面试 Q7（10 台能否扛 3000QPS）+ Q10（性能优化方案）的补充。核心短板：冗余系数偏低（说 20-30% vs 标准 50-100%）+ 遗漏代码级/基础设施/兜底策略。

### 容量规划黄金公式

**核心公式**：
```
机器数 = (峰值 QPS × 冗余系数) ÷ 单机稳态 QPS
```

**三大关键参数**：
| 参数 | 常见值 | 说明 |
|------|--------|------|
| **压测上限** | CPU 95% / GC 频繁 / P99 暴涨 | 极限水位，不作为规划基准 |
| **稳态水位** | CPU 50-60% / 压测上限 × 50% | 实际规划基准 |
| **冗余系数** | 1.5-2（预留 50-100%） | 应对抖动、长尾、依赖 |

**举例**：
- 单机压测上限 = 300 QPS → 稳态水位 = 150 QPS
- 峰值 = 3000 QPS × 冗余 1.5 = 4500 QPS
- 需要机器数 = 4500 ÷ 150 = **30 台**（不是 10 台！）

**为什么用户说的 20-30% 冗余不够**：
- **长尾流量**：P99 耗时可能是 P50 的 100 倍，长尾请求让某台机器先被打爆
- **GC 抖动**：STW 期间请求堆积，恢复时集中涌入
- **慢查询**：偶发 SQL 卡住，占用连接池
- **依赖资源抖动**：DB/Redis/下游接口抖动会连带影响应用

### 流量倾斜的三种原因

| 原因 | 表现 | 应对 |
|------|------|------|
| **长尾请求** | P99 耗时远超 P50 | 超时控制、异步化、限流降级 |
| **热点数据** | 某些 key/用户被集中访问 | 分片、本地缓存、热点探测 |
| **连接粘性** | Session/Keep-Alive 导致连接倾斜 | 会话粘性路由、无状态化 |

### 依赖资源瓶颈四类

即使应用层能扛，依赖资源常先崩：
1. **数据库**：连接池、CPU、锁、I/O（DB 单点通常比应用先崩）
2. **缓存**：Redis 单分片 QPS 上限、内存限制
3. **下游接口**：第三方 API、消息队列、RPC 服务
4. **网络**：带宽、TCP 连接数、NAT 表

### 负载均衡策略对比

| 策略 | 特点 | 适用场景 |
|------|------|---------|
| **轮询 RR** | 均分、简单 | 机器同质 |
| **加权 RR** | 按性能权重 | 机器异构 |
| **IP Hash** | 同 IP 固定机器 | 需要会话保持 |
| **一致性 Hash** | 扩缩容只影响小部分 | 缓存集群 |
| **最少连接** | 按实时负载分配 | 请求耗时不均 |
| **响应时间权重** | 按历史响应时间 | 智能调度 |

### 限流降级兜底三件套

| 手段 | 实现 | 兜底场景 |
|------|------|---------|
| **限流** | Sentinel 单机 + 网关全局 + Redis 全局限流 | 流量激增 |
| **熔断** | Resilience4j/Hystrix | 下游慢调用 |
| **降级** | 缓存兜底 / 静态兜底 / 异步兜底 | 依赖不可用 |

### 性能优化五步法（完整版）

> Q10 的补充：不只是分层，还包括**代码级 + 基础设施 + 兜底**四步。

**Step 0 · 前置判断**（80% 候选人跳过）：
- 先定位瓶颈（不要盲改代码）
- 明确业务指标（QPS/P99/并发）
- 明确优化目标（P99 从 500ms 降到 100ms）
- 权衡成本 vs 收益（避免过度优化）

**Step 1 · 定位瓶颈**：
- 链路追踪（SkyWalking/Jaeger/Zipkin）
- 火焰图（Flame Graph）看 CPU 热点
- 慢查询日志（`SHOW SLOW QUERIES`）
- APM 指标（Prometheus + Grafana）

**Step 2 · 代码级优化**（最常被忽略）：
- **N+1 查询**：ORM 主查询触发 N 次子查询，改 `JOIN` 或 `foreach` 批处理
- **批处理**：批量插入 `INSERT ... VALUES (...),(...),(...)` 代替循环单条
- **并行调用**：`CompletableFuture.supplyAsync` 并行调下游服务，注意：
  - 用独立线程池（不要用 `ForkJoinPool.commonPool` 会互相阻塞）
  - 超时控制（`orTimeout`）
  - 异常兜底（`exceptionally`）
- **异步化**：耗时操作扔 MQ，主流程立即返回
- **本地计算**：减少远程调用，能算的算在本地

**Step 3 · 缓存优化**：
- **多级缓存**：Caffeine 本地 + Redis 远程，减少网络开销
- **缓存预热**：启动时预加载热点数据
- **穿透/击穿/雪崩防护**：布隆过滤器、互斥锁、过期时间加随机数
- **业务权衡**：能接受不一致就缓存，实时性要求高就不缓存或短过期

**Step 4 · 基础设施调优**：
- **JVM**：G1/ZGC 收集器、堆大小、元空间、直接内存
- **线程池**：核心线程数、队列策略（`CallerRunsPolicy` vs `AbortPolicy`）、拒绝策略
- **连接池**：HikariCP（DB）、OkHttp/Apache HC（HTTP）
- **OS 参数**：`somaxconn`、`tcp_tw_reuse`、`file-max`

**Step 5 · 架构演进**：
- **读写分离**：主从复制、CQRS
- **分库分表**：水平分片，按 user_id/hash 分片
- **异步化架构**：主流程同步 + 副作用异步
- **换技术栈**：MySQL（事务）→ ClickHouse（OLAP）→ ES（搜索）→ HBase（海量 KV）
- **CDN 静态化**：前端资源、图片走 CDN

**Step 6 · 兜底策略**：
- **限流**：Sentinel 单机 + 网关全局 + Redis 全局限流
- **熔断**：Resilience4j 熔断下游慢调用
- **降级**：非核心接口跳过、缓存兜底、静态兜底
- **预热**：服务预热、灰度发布（1% → 50% → 100%）
- **压测**：JMeter/wrk/ab，量化优化前后对比（不量化 = 没优化）

### 性能优化案例复盘（订单查询）

**优化前**：P99 = 800ms，QPS = 500
**优化后**：P99 = 120ms，QPS = 3000

**流程**：
1. **定位**：SkyWalking 链路追踪发现 N+1 查询（一次查订单触发 100+ 次查商品）
2. **优化**：改 `JOIN` + 本地缓存商品数据
3. **调优**：HikariCP 连接池调大、G1 GC 调参
4. **兜底**：加 Redis 缓存兜底、Sentinel 限流保护
5. **压测**：JMeter 前后对比量化验证

### 不同数据库适用场景

| 数据库 | 适用场景 |
|--------|---------|
| **MySQL** | 事务、强一致、中等数据量 |
| **ClickHouse** | OLAP 分析、海量聚合查询、列存 |
| **Elasticsearch** | 全文搜索、复杂查询、日志 |
| **HBase** | 宽表、海量 KV、非结构化 |
| **Redis** | 缓存、实时排行、分布式锁 |
| **MongoDB** | 文档型、灵活 Schema |

### Anki 候选卡片补充

1. **正**：容量规划黄金公式？**反**：机器数 = (峰值 QPS × 冗余系数) ÷ 单机稳态 QPS
2. **正**：稳态水位和冗余系数的经验值？**反**：稳态水位 = 压测上限 × 50%（CPU 50-60%）；冗余系数 = 1.5-2（预留 50-100%）
3. **正**：流量倾斜的三种原因？**反**：长尾请求（P99 vs P50）/ 热点数据 / 连接粘性
4. **正**：性能优化五步法？**反**：Step1 定位（链路追踪+火焰图）/ Step2 代码（N+1/批处理/CompletableFuture）/ Step3 缓存（多级+穿透防护）/ Step4 基础设施（JVM/线程池/连接池）/ Step5 架构演进（分库分表/CQRS/换技术栈）
5. **正**：CompletableFuture 并行调用注意事项？**反**：独立线程池（不用 commonPool）+ orTimeout 超时控制 + exceptionally 异常兜底
6. **正**：性能优化兜底三件套？**反**：限流（Sentinel 单机+网关+Redis 全局）/ 熔断（Resilience4j）/ 降级（缓存/静态/异步兜底）

---

*最后更新：2026-10-08（追加容量规划黄金公式 + 性能优化五步法完整版）*
