跳到主要内容
预计阅读 29 分钟

01 | 初识系统设计 —— 为什么需要系统设计、设计方法论、估算技巧

一个好的系统不是凭空产生的,它源于对问题的深刻理解与对方案的反复权衡。


开篇自测

在正式开始之前,请先回答以下三个问题,检验你对系统设计的初始认知:

  1. 当面对一个全新的业务需求时,你会从哪几个维度来思考系统的整体方案?
  2. 如果产品经理告诉你”日活用户 500 万”,你能据此估算出系统需要承载的 QPS 吗?
  3. 你认为”架构设计”和”编码实现”之间最本质的区别是什么?

带着这些问题,我们正式进入系统设计的世界。


一、为什么需要系统设计

1.1 从一次线上事故说起

某社交平台在一次运营活动中,预期流量为日常的 5 倍。开发团队仅对数据库做了简单的主从配置,便上线了活动。活动开始后 10 分钟,数据库连接池被打满,缓存大面积失效,整个系统响应时间从 200ms 飙升至 15 秒,最终不得不紧急下线活动。

事后复盘,团队发现问题的根源并非代码 Bug,而是缺乏系统性的架构思考:没有做容量估算、没有设计降级方案、没有对热点数据做缓存预热。

这个案例揭示了一个事实:代码写得再好,如果系统设计不合理,在规模和复杂度面前都将不堪一击

1.2 系统设计解决什么问题

系统设计关注的核心问题可以用三个关键词概括:

  • 规模:当用户从 1 万增长到 1000 万时,系统如何平滑扩展?
  • 复杂度:当业务模块从 3 个增长到 30 个时,如何保持系统的可维护性?
  • 可靠性:当某个组件发生故障时,如何保证整体服务不受影响?
                    系统设计的核心关注点
    +------------------------------------------------+
    |                                                |
    |   规模 (Scale)                                  |
    |   - 用户量增长                                   |
    |   - 数据量膨胀                                   |
    |   - 请求量激增                                   |
    |                                                |
    |   复杂度 (Complexity)                            |
    |   - 业务逻辑交织                                 |
    |   - 技术栈多样                                   |
    |   - 团队协作困难                                 |
    |                                                |
    |   可靠性 (Reliability)                            |
    |   - 硬件故障                                     |
    |   - 软件缺陷                                     |
    |   - 人为操作失误                                 |
    |                                                |
    +------------------------------------------------+

1.3 系统设计与编码的本质差异

编码的核心思维是逻辑与实现——给定输入,产生正确的输出。而系统设计的核心思维是判断与取舍——在多种可行方案中,选择最适合当前场景的那个。

一个典型的例子:实现用户注册功能,编码层面关心的是参数校验、密码加密、数据入库;而系统设计层面关心的是——注册信息存在哪里(MySQL 还是 MongoDB)、如何防止重复注册(唯一索引还是分布式锁)、注册后的消息通知是同步还是异步、如果注册量激增到每秒 1 万次该怎么办。

编程解决的是”如何做对”,系统设计解决的是”如何做好”。


二、系统设计方法论

2.1 四步设计法

面对任何一个系统设计问题,都可以按照以下四个步骤来展开:

第一步:明确需求与约束

  • 功能需求:系统要做什么?核心用例有哪些?
  • 非功能需求:性能指标、可用性目标、数据一致性要求
  • 约束条件:预算、团队规模、技术栈限制、上线时间

第二步:粗略估算

  • 用户规模、数据规模、请求量级
  • 存储需求、带宽需求、计算资源需求

第三步:概要设计

  • 划分核心模块和组件
  • 确定数据流向和通信方式
  • 绘制系统拓扑图

第四步:深入设计与权衡

  • 针对核心模块做详细方案
  • 识别瓶颈点并提出优化策略
  • 讨论方案的 Trade-off
    明确需求           粗略估算           概要设计           深入设计
  +-----------+     +-----------+     +-----------+     +-----------+
  | 功能需求  | --> | 用户规模  | --> | 模块划分  | --> | 详细方案  |
  | 非功能需求| --> | 数据规模  | --> | 数据流向  | --> | 瓶颈识别  |
  | 约束条件  | --> | 资源需求  | --> | 拓扑结构  | --> | Trade-off |
  +-----------+     +-----------+     +-----------+     +-----------+

2.2 需求分析的技巧

很多人在做系统设计时,第一反应是”用什么技术”,但更重要的是先问清楚”要解决什么问题”。

一个好的需求分析应该覆盖以下维度:

维度关键问题示例
用户谁在用?用户量级?DAU 500 万,峰值 QPS 5000
功能核心功能是什么?发消息、查历史、推送通知
数据数据量多大?增长速率?日增 1 亿条消息,保留 3 年
性能延迟要求?吞吐量要求?P99 延迟 < 200ms
可用性能接受多长时间宕机?年可用性 99.99%(年宕机 < 53 分钟)
一致性数据能否有短暂不一致?允许最终一致性,延迟 < 5 秒

2.3 “合适”优于”先进”

系统设计中最常见的误区之一是过度设计。一个日活 1000 人的内部工具,不需要微服务架构;一个读多写少的博客系统,不需要分库分表。

三条实用原则:

  • 简单原则:能用简单方案解决的问题,不要引入复杂方案
  • 演进原则:先满足当前需求,再根据增长趋势逐步优化
  • 适度原则:预留 2-3 倍的容量冗余,而非 100 倍

三、容量估算:系统设计的第一课

3.1 为什么要做容量估算

容量估算是系统设计的起点。它决定了你需要多少台服务器、多大的数据库、多宽的带宽。没有估算,一切架构决策都是空中楼阁。

容量估算的目标不是精确到个位数,而是确定数量级——是 100 QPS 还是 10000 QPS,因为这两者的架构方案完全不同。

3.2 常用估算数据

在做估算之前,你需要记住一些常用的基准数据:

延迟数据(2020 年代参考值,量级参考,实际因硬件型号和配置而异)

操作耗时
L1 缓存引用1 ns
L2 缓存引用4 ns
主内存引用100 ns
SSD 随机读16 us
机械硬盘寻道4 ms
同机房网络往返0.5 ms
跨城网络往返30 ms
跨洲网络往返150 ms

吞吐量参考值

组件参考吞吐量
单台 MySQL(普通查询)3000-5000 QPS
单台 Redis(简单命令)80000-100000 QPS
单台 Nginx(静态文件)50000-100000 QPS
单台应用服务器(业务逻辑)500-2000 QPS

存储参考值

数据大小
一条推文(280 字 UTF-8)最多约 1120 字节
一张缩略图~20 KB
一张高清图~500 KB
一分钟标清视频~10 MB

3.3 估算实战:社交平台消息系统

背景假设

  • DAU(日活用户):1000 万
  • 每个用户每天平均发送 20 条消息
  • 每条消息平均 200 字节
  • 消息保留 5 年
  • 读写比 10:1

QPS 估算

写入 QPS:
  日消息总量 = 1000 万 x 20 = 2 亿条/天
  平均写入 QPS = 2 亿 / 86400 ≈ 2300 QPS
  峰值写入 QPS = 2300 x 3(峰值系数)≈ 7000 QPS

读取 QPS:
  平均读取 QPS = 2300 x 10 = 23000 QPS
  峰值读取 QPS = 23000 x 3 ≈ 70000 QPS

存储估算

日存储增量 = 2 亿 x 200 字节 = 40 GB/天
年存储增量 = 40 GB x 365 ≈ 14.6 TB/年
5 年存储量 = 14.6 TB x 5 ≈ 73 TB

带宽估算

峰值入站带宽 = 7000 x 200 字节 = 1.4 MB/s ≈ 11.2 Mbps
峰值出站带宽 = 70000 x 200 字节 = 14 MB/s ≈ 112 Mbps

初步结论

  • 写入 QPS 7000,一台 MySQL 难以承载,需要考虑分库或引入消息队列削峰
  • 读取 QPS 70000,非常适合引入 Redis 缓存层
  • 73TB 存储量,需要考虑数据分片和冷热分离

3.4 常用数量级速算技巧

记住以下几个关键换算,能让你在面试和讨论中快速估算:

换算
1 天有多少秒~86400 ≈ 10^5(约 10 万)
1 天有多少毫秒~86400000 ≈ 10^8(粗略近似,实际为 8.64×10^7)
2.5 亿 / 天 ≈ ? QPS≈ 3000 QPS
1 QPS 对应 ? 次/天≈ 86400 ≈ 10 万次/天
1 MB/s ≈ ? Mbps≈ 8 Mbps
1 TB ≈ 多少条 1KB 记录≈ 10 亿条

四、系统设计中的核心概念

4.1 性能指标体系

衡量一个系统好不好,需要一套可量化的指标:

响应时间(Latency)

  • P50:50% 的请求在该时间内完成(中位数)
  • P95:95% 的请求在该时间内完成
  • P99:99% 的请求在该时间内完成

为什么要关注尾部延迟(P99/P999)?因为体验最差的那 1% 用户,往往是你最重要的用户——他们的请求数据量更大、操作更复杂。

吞吐量(Throughput)

  • QPS(Queries Per Second):每秒查询数
  • TPS(Transactions Per Second):每秒事务数
  • RPS(Requests Per Second):每秒请求数

可用性(Availability)

用”几个 9”来衡量:

等级可用性年停机时间
2 个 999%3.65 天
3 个 999.9%8.76 小时
4 个 999.99%52.6 分钟
5 个 999.999%5.26 分钟

一般来说,核心支付系统追求 4 个 9,普通业务系统 3 个 9 即可。

4.2 可扩展性的两种方式

垂直扩展 (Scale Up)                水平扩展 (Scale Out)
+-------------------+             +-------+ +-------+ +-------+
|                   |             |       | |       | |       |
|   更强的单机       |             | 机器1 | | 机器2 | | 机器3 |
|   - 更多 CPU      |             |       | |       | |       |
|   - 更大内存       |             +-------+ +-------+ +-------+
|   - 更快磁盘       |             +-------+ +-------+ +-------+
|                   |             |       | |       | |       |
+-------------------+             | 机器4 | | 机器5 | | 机器6 |
                                  |       | |       | |       |
                                  +-------+ +-------+ +-------+

优点: 简单,无需改代码             优点: 理论上可无限扩展
缺点: 存在物理上限,成本高         缺点: 增加系统复杂度

现代互联网系统几乎都以水平扩展为主,因为垂直扩展存在天花板,而水平扩展则可以按需线性增长。

4.3 单点故障与冗余

**单点故障(SPOF)**是系统设计中最大的隐患。所谓单点,就是某个组件一旦失效,整个系统就无法工作。

消除单点的核心手段是冗余

  • 应用层冗余:多实例部署 + 负载均衡
  • 数据层冗余:主从复制 + 自动故障转移
  • 网络层冗余:多线路接入 + DNS 故障切换
             消除单点故障的典型架构

                    用户请求
                       |
                  +---------+
                  |  DNS    |(多 IP 轮询)
                  +---------+
                   /        \
             +--------+  +--------+
             |  LB-1  |  |  LB-2  |   负载均衡层(主备)
             +--------+  +--------+
              /   |   \
         +-----+ +-----+ +-----+
         |App1 | |App2 | |App3 |       应用层(多实例)
         +-----+ +-----+ +-----+
              \    |    /
         +--------+ +--------+
         |Master  | |Slave   |        数据层(主从复制)
         |  DB    | |  DB    |
         +--------+ +--------+

五、架构设计的常见模式

5.1 分层架构

分层架构是最经典的架构模式,它将系统按职责划分为多个层次,每一层只与相邻层交互。

+--------------------------------------------------+
|                  表现层 (Presentation)              |
|          Web 页面 / 移动端 / API 网关              |
+--------------------------------------------------+
                         |
+--------------------------------------------------+
|                  业务逻辑层 (Business)              |
|          核心业务处理 / 规则引擎 / 工作流           |
+--------------------------------------------------+
                         |
+--------------------------------------------------+
|                  数据访问层 (Data Access)           |
|          ORM / DAO / Repository                    |
+--------------------------------------------------+
                         |
+--------------------------------------------------+
|                  存储层 (Storage)                   |
|          MySQL / Redis / MongoDB / ES              |
+--------------------------------------------------+

分层架构的优势在于职责清晰、易于测试、可独立替换。但也存在性能损耗(每层调用都有开销)和过度抽象的问题。

5.2 客户端-服务器模式

这是 Web 应用中最基础的模式。客户端负责展示和交互,服务器负责业务处理和数据存储。

在移动互联网时代,这种模式进一步演化为:

  • 瘦客户端:大部分逻辑在服务器端(如传统 Web 页面)
  • 胖客户端:客户端承担较多逻辑(如 SPA 单页应用、Native App)
  • BFF 模式:为不同客户端提供专门的后端服务层

5.3 事件驱动架构

事件驱动架构通过异步消息在组件之间传递信息,实现松耦合:

  生产者 A                        消费者 X
  +--------+    +-----------+    +--------+
  | 订单   | -> |           | -> | 库存   |
  | 服务   |    |  消息队列  |    | 服务   |
  +--------+    |           |    +--------+
                |  (Kafka/  |
  生产者 B      |  RabbitMQ)|    消费者 Y
  +--------+    |           |    +--------+
  | 支付   | -> |           | -> | 通知   |
  | 服务   |    +-----------+    | 服务   |
  +--------+                     +--------+

优势:组件解耦、易于扩展、削峰填谷。劣势:调试困难、消息可能丢失或重复、增加系统复杂度。


六、从理论到实践:设计一个 URL 缩短服务

6.1 需求分析

为了将前面的方法论落地,我们以一个经典的系统设计题——URL 缩短服务来做一次完整练习。

功能需求

  • 用户输入一个长 URL,系统返回一个短 URL
  • 用户访问短 URL 时,系统重定向到对应的长 URL
  • 短链有效期 5 年

非功能需求

  • 每天生成 1 亿个短链
  • 读写比 100:1
  • 重定向延迟 < 50ms
  • 可用性 99.99%

6.2 容量估算

写入 QPS = 1 亿 / 86400 ≈ 1200 QPS
峰值写入 QPS ≈ 3600 QPS

读取 QPS = 1200 x 100 = 120000 QPS
峰值读取 QPS ≈ 360000 QPS

5 年短链总量 = 1 亿 x 365 x 5 = 1825 亿 ≈ 2000 亿条

每条记录大小(短码 + 长 URL + 时间戳)≈ 500 字节
总存储 = 2000 亿 x 500 字节 = 100 TB

6.3 概要设计

            +-------------------------------------------+
            |              客户端 / 浏览器               |
            +-------------------------------------------+
                              |
                       +-------------+
                       |  负载均衡器  |
                       +-------------+
                        /           \
               +----------+     +----------+
               | API 服务1|     | API 服务2|   (可水平扩展)
               +----------+     +----------+
                    |                  |
          +---------+---------+--------+---------+
          |                   |                  |
    +----------+        +---------+        +----------+
    | 短码生成 |        |  缓存层  |        |  数据库   |
    |  服务    |        |  Redis  |        |  (分片)   |
    +----------+        +---------+        +----------+

6.4 关键设计决策

短码生成方案:使用 Base62 编码(a-z, A-Z, 0-9),7 位短码可以表示 62^7 ≈ 3.5 万亿种组合,远超 2000 亿的需求。

存储方案:使用 NoSQL(如 DynamoDB 或 Cassandra),因为数据结构简单、读写量大、不需要复杂查询。

缓存策略:热门短链缓存到 Redis,缓存命中率预计可达 80% 以上,将大部分读请求拦截在缓存层。

这个案例虽然简单,但完整展示了系统设计的四步法。后续章节中,我们将对其中涉及的每一项技术做深入探讨。


思考题

  1. 如果上述 URL 缩短服务要支持短链自定义(用户指定短码),系统设计上需要做哪些调整?需要考虑哪些冲突和并发问题?

  2. 在容量估算中,我们使用了”峰值系数 3”来估算峰值 QPS。在你的实际工作中,不同类型的业务系统(如电商、社交、工具类),峰值系数通常是多少?影响峰值系数的因素有哪些?

  3. 有人说”架构设计就是做选择题”,你同意吗?请结合自己的经历举出一个你做过的架构取舍决策。


结尾自测

完成本章学习后,请尝试回答以下五个问题:

  1. 系统设计的四步法分别是什么?每一步的核心产出是什么?

    • :明确需求与约束(需求文档)、粗略估算(量级数据)、概要设计(系统拓扑图)、深入设计与权衡(详细方案与 Trade-off 分析)。
  2. DAU 为 2000 万的社交应用,若每用户日均产生 10 次 API 调用,峰值系数为 5,峰值 QPS 约为多少?

    • :平均 QPS = 2000 万 x 10 / 86400 ≈ 2300,峰值 QPS ≈ 2300 x 5 = 11500 QPS。
  3. “四个 9”的可用性意味着年停机时间不超过多少?

    • :52.6 分钟。
  4. 垂直扩展和水平扩展的核心区别是什么?为什么现代互联网系统更倾向于水平扩展?

    • :垂直扩展是增强单机性能,水平扩展是增加机器数量。水平扩展没有物理上限,且可以按需线性扩容,更适合互联网业务的弹性需求。
  5. 为什么要关注 P99 延迟而不仅仅是平均延迟?

    • :平均延迟会掩盖长尾问题,P99 反映的是绝大多数用户的真实体验,而那 1% 的慢请求背后往往是系统的瓶颈点,可能影响到最重要的用户群体。

下一章预告:了解了系统设计的基础方法论之后,我们将深入高性能架构的世界,从缓存策略到数据库优化,一步步打造能够承载海量流量的系统。

购买课程解锁全部内容

面试晋升必学:11 章掌握系统设计

¥29.90