HiHuo
首页
博客
手册
工具
关于
首页
博客
手册
工具
关于
  • 系统设计实战

    • 系统设计面试教程
    • 系统设计方法论
    • 01-短链系统设计
    • 02 - 秒杀系统设计
    • 03 - IM 即时通讯系统设计
    • 04 - Feed 流系统设计
    • 05 - 分布式 ID 生成器设计
    • 06 - 限流系统设计
    • 第7章:搜索引擎设计
    • 08 - 推荐系统设计
    • 09 - 支付系统设计
    • 10 - 电商系统设计
    • 11 - 直播系统设计
    • 第12章:缓存系统设计
    • 第13章:消息队列设计
    • 第14章:分布式事务
    • 15 - 监控系统设计

系统设计方法论

架构师面试的核心能力:如何系统化地设计一个完整的系统

📖 章节概述

系统设计面试不是考察你是否记住了某个技术细节,而是考察你如何将复杂问题拆解为可落地的技术方案的能力。本章将介绍完整的系统设计方法论,帮助你建立结构化的思维框架。

学习目标

  • 掌握系统设计的完整流程(从需求到架构的7个步骤)
  • 学会容量估算(QPS、存储、带宽的计算方法)
  • 理解架构演进(从MVP到高可用的路径)
  • 掌握技术选型的权衡方法(trade-off分析)
  • 熟悉面试技巧(如何沟通、如何画图、如何应对追问)

🔄 一、系统设计的完整流程

系统设计面试通常是45-60分钟,需要在有限时间内完成以下7个步骤:

┌─────────────────────────────────────────────────────────────┐
│                    系统设计流程(45-60分钟)                │
├─────────────────────────────────────────────────────────────┤
│ 1. 需求澄清(5-8分钟)    → 功能范围、数据规模、性能要求    │
│ 2. 容量估算(5-8分钟)    → QPS、存储、带宽计算            │
│ 3. 接口设计(5-8分钟)    → API定义、请求/响应格式         │
│ 4. 数据模型(5-8分钟)    → 表结构、索引、分库分表         │
│ 5. 架构设计(15-20分钟)  → 画架构图、讲解核心流程        │
│ 6. 深入细节(10-15分钟)  → 技术选型、优化方案            │
│ 7. 总结收尾(3-5分钟)    → 回顾设计、讨论tradeoff        │
└─────────────────────────────────────────────────────────────┘

⚠️ 时间分配建议

阶段时间占比重要程度注意事项
需求澄清10-15%必做,避免理解偏差
容量估算10-15%展示数据敏感度
接口设计10-15%可选,看时间
数据模型10-15%核心表结构必须有
架构设计30-40%核心,决定面试成败
深入细节20-30%展示技术深度
总结收尾5-10%查漏补缺

二、步骤1:需求澄清(Clarify Requirements)

1️⃣ 为什么要澄清需求?

面试题通常故意模糊,例如:

  • "设计一个短链系统"
  • "设计一个秒杀系统"
  • "设计一个IM系统"

你需要通过提问来明确范围,避免:

  • 设计了不需要的功能(过度设计)
  • 遗漏了核心功能(理解偏差)
  • 性能指标不清楚(无法优化)

2️⃣ 需求澄清的三个维度

A. 功能需求(Functional Requirements)

通过提问明确核心功能和边界:

示例:设计短链系统

问题为什么要问影响的设计决策
"是否需要自定义短链?"核心功能范围如果需要,要考虑冲突检测
"是否需要统计点击量?"是否需要统计系统需要设计统计表和异步写入
"短链是否有有效期?"数据清理策略需要定时任务清理过期数据
"是否需要防刷?"安全需求需要限流和风控模块

提问模板:

1. 这个系统的核心功能是什么?(3-5个)
2. 是否需要XXX功能?(列出可能的扩展功能)
3. 对于YYY场景,我们需要支持吗?
4. 有没有不需要考虑的功能?(明确不做什么)

B. 非功能需求(Non-Functional Requirements)

明确性能、可用性、一致性的要求:

维度问题影响的设计
性能"预期QPS是多少?峰值QPS?"决定是否需要缓存、分库分表
可用性"可用性要求是99.9%还是99.99%?"决定多活、容灾方案
一致性"能否接受最终一致性?"决定是否使用分布式事务
延迟"响应时间要求是多少?P99?"决定缓存策略、数据库优化

常见的非功能需求:

- 性能:QPS(Queries Per Second)、TPS(Transactions Per Second)
- 延迟:P50、P95、P99、P999
- 可用性:99%、99.9%(3个9)、99.99%(4个9)
- 一致性:强一致性、最终一致性、因果一致性
- 扩展性:水平扩展能力、支持的用户规模

C. 数据规模(Scale)

明确数据量和增长速度:

示例问题:

  • "日活用户(DAU)是多少?月活(MAU)?"
  • "每个用户平均产生多少数据?"
  • "数据保留多久?是否需要归档?"
  • "预期多久达到什么规模?"

为什么重要:

  • 决定是否需要分库分表
  • 决定存储方案(MySQL、MongoDB、HBase)
  • 决定缓存策略(缓存多少数据)

3️⃣ 需求澄清的输出

完成需求澄清后,你应该得到:

功能清单:

核心功能(Must Have):
1. 生成短链
2. 短链跳转
3. 统计点击量

扩展功能(Nice to Have):
4. 自定义短链
5. 二维码生成
6. 链接有效期

性能指标:

- 日活用户:1000万
- 生成短链QPS:1000
- 跳转QPS:10000(读写比 10:1)
- 响应时间:P99 < 100ms
- 可用性:99.9%

数据规模:

- 每天生成100万条短链
- 数据保留1年
- 总数据量:100万 × 365 = 3.65亿条

三、步骤2:容量估算(Capacity Estimation)

容量估算展示你的数据敏感度和工程经验,是面试的加分项。

1️⃣ 估算的三个维度

A. QPS估算(Queries Per Second)

从DAU推算QPS:

公式:QPS = DAU × 每用户操作次数 / 86400秒 × 峰值系数

步骤:
1. DAU(日活用户)
2. 每用户操作次数
3. 平均QPS = 总操作 / 86400
4. 峰值QPS = 平均QPS × 峰值系数(通常2-5倍)

示例:短链系统

假设:
- DAU = 1000万
- 每用户每天点击10次短链
- 峰值系数 = 3倍

计算:
- 总操作 = 1000万 × 10 = 1亿次/天
- 平均QPS = 1亿 / 86400 ≈ 1157 QPS
- 峰值QPS = 1157 × 3 ≈ 3500 QPS

读写比例:

假设生成:跳转 = 1:10
- 写QPS(生成短链)= 3500 / 11 ≈ 320 QPS
- 读QPS(跳转)= 3500 × 10 / 11 ≈ 3200 QPS

B. 存储估算(Storage)

公式:

存储 = 单条数据大小 × 数据条数 × 冗余系数

示例:短链系统

表结构(简化):
- short_url: VARCHAR(10) = 10 bytes
- long_url: VARCHAR(2048) = 2048 bytes
- created_at: TIMESTAMP = 8 bytes
- click_count: INT = 4 bytes
总计:2070 bytes ≈ 2KB

数据量:
- 每天生成100万条
- 保留1年:100万 × 365 = 3.65亿条

存储计算:
- 裸数据:3.65亿 × 2KB = 730GB
- 索引:730GB × 30% = 219GB
- 冗余(主从):(730 + 219) × 2 = 1.9TB

结论:需要2TB存储

C. 带宽估算(Bandwidth)

公式:

带宽 = QPS × 平均数据大小

示例:短链系统

流量计算:
- 跳转请求:3200 QPS × 0.5KB = 1.6 MB/s ≈ 12.8 Mbps
- 跳转响应(302重定向):3200 QPS × 2KB = 6.4 MB/s ≈ 51.2 Mbps
- 总带宽:12.8 + 51.2 = 64 Mbps

结论:需要100 Mbps带宽(留余量)

2️⃣ 记住这些常用数字

时间单位:

1秒 = 1,000 毫秒(ms) = 1,000,000 微秒(μs) = 1,000,000,000 纳秒(ns)
1天 = 86,400 秒 ≈ 10^5 秒(估算时)

存储单位:

1 KB = 1,024 bytes ≈ 10^3 bytes
1 MB = 1,024 KB ≈ 10^6 bytes
1 GB = 1,024 MB ≈ 10^9 bytes
1 TB = 1,024 GB ≈ 10^12 bytes

常见数据大小:

- 一个字符:1 byte
- 一个整数(INT):4 bytes
- 一个时间戳(TIMESTAMP):8 bytes
- 一个UUID:16 bytes (128 bits)
- 一张图片:100 KB - 1 MB
- 一个视频:10 MB - 100 MB

系统性能参考:

- L1缓存访问:0.5 ns
- L2缓存访问:7 ns
- 内存访问:100 ns
- SSD随机读:150 μs
- HDD磁盘寻道:10 ms
- 网络:同城1ms,跨城10-50ms

数据库性能:

- MySQL单机:1万 QPS(读),5千 QPS(写)
- Redis单机:10万 QPS(读写)
- MongoDB单机:1万 QPS

3️⃣ 容量估算的输出

完成容量估算后,写在白板上:

┌─────────────────────────────────────────────────────────────┐
│                    容量估算结果                             │
├─────────────────────────────────────────────────────────────┤
│ QPS:                                                        │
│   - 峰值读QPS: 3,200                                        │
│   - 峰值写QPS: 320                                          │
│                                                             │
│ 存储:                                                       │
│   - 数据量: 3.65亿条                                        │
│   - 存储空间: 2TB(含索引和冗余)                            │
│                                                             │
│ 带宽:                                                       │
│   - 出口带宽: 64 Mbps → 需要100 Mbps                        │
└─────────────────────────────────────────────────────────────┘

🔌 四、步骤3:接口设计(API Design)

接口设计是可选步骤,如果时间紧张可以跳过,但建议至少列出核心API。

1️⃣ RESTful API设计原则

HTTP方法:
- GET:查询资源
- POST:创建资源
- PUT:更新资源(完整更新)
- PATCH:更新资源(部分更新)
- DELETE:删除资源

2️⃣ 示例:短链系统API

# 1. 生成短链
POST /api/v1/shorten
Request:
{
  "long_url": "https://www.example.com/very/long/url",
  "custom_alias": "my-link",  // 可选,自定义短链
  "expire_at": "2024-12-31"   // 可选,过期时间
}

Response:
{
  "code": 0,
  "message": "success",
  "data": {
    "short_url": "https://short.ly/abc123",
    "short_code": "abc123",
    "long_url": "https://www.example.com/very/long/url",
    "created_at": "2024-01-01T00:00:00Z",
    "expire_at": "2024-12-31T23:59:59Z"
  }
}

# 2. 短链跳转(HTTP 302重定向)
GET /{short_code}
Response:
HTTP/1.1 302 Found
Location: https://www.example.com/very/long/url

# 3. 查询短链统计
GET /api/v1/stats/{short_code}
Response:
{
  "code": 0,
  "data": {
    "short_code": "abc123",
    "click_count": 12345,
    "created_at": "2024-01-01T00:00:00Z",
    "daily_stats": [
      {"date": "2024-01-01", "clicks": 100},
      {"date": "2024-01-02", "clicks": 150}
    ]
  }
}

3️⃣ API设计的最佳实践

使用版本号:/api/v1/,便于后续升级 RESTful风格:资源名词复数,如 /users、/orders统一响应格式:包含 code、message、data错误码设计:定义清晰的错误码 分页参数:page、page_size、total过滤排序:支持 filter、sort、order

错误码示例:

{
  "code": 4001,
  "message": "短链已存在",
  "data": null
}

错误码规范:
- 0: 成功
- 1xxx: 通用错误(1001: 参数错误,1002: 未授权)
- 2xxx: 业务错误(2001: 短链不存在,2002: 短链已过期)
- 3xxx: 系统错误(3001: 数据库错误,3002: 缓存错误)

🗄️ 五、步骤4:数据模型设计(Data Model)

数据库设计是系统的核心骨架,必须认真设计。

1️⃣ 表结构设计原则

三范式(但可以适当冗余以提升性能) 索引设计(根据查询场景设计索引) 分库分表(单表超过500万-1000万行考虑) 字段类型(选择合适的类型,节省空间)

2️⃣ 示例:短链系统表设计

核心表:url_mapping(短链映射表)

CREATE TABLE url_mapping (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    short_code CHAR(8) NOT NULL COMMENT '短链码(Base62编码)',
    long_url VARCHAR(2048) NOT NULL COMMENT '原始长链接',
    user_id BIGINT UNSIGNED DEFAULT NULL COMMENT '创建用户ID',
    click_count INT UNSIGNED DEFAULT 0 COMMENT '点击次数',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    expire_at TIMESTAMP NULL COMMENT '过期时间',

    UNIQUE KEY uk_short_code (short_code),
    KEY idx_user_id (user_id),
    KEY idx_created_at (created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='短链映射表';

统计表:url_stats(访问统计表)

CREATE TABLE url_stats (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    short_code CHAR(8) NOT NULL COMMENT '短链码',
    access_date DATE NOT NULL COMMENT '访问日期',
    click_count INT UNSIGNED DEFAULT 0 COMMENT '当日点击次数',

    UNIQUE KEY uk_short_code_date (short_code, access_date),
    KEY idx_access_date (access_date)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='短链访问统计表';

3️⃣ 分库分表策略

何时需要分库分表?

- 单表数据量超过500万-1000万行
- 单表磁盘文件超过2GB
- 单表索引过大,查询性能下降

分库分表方案:

方案1:按短链码Hash分表

表名:url_mapping_0, url_mapping_1, ..., url_mapping_99(100张表)
路由规则:hash(short_code) % 100

方案2:按时间范围分表

表名:url_mapping_202401, url_mapping_202402, ...
路由规则:根据created_at年月分表
优点:历史数据可归档
缺点:热点数据集中在最新表

方案3:按用户ID分库

库名:db_0, db_1, ..., db_15(16个库)
路由规则:hash(user_id) % 16
优点:用户维度查询高效
缺点:需要全局ID生成器

4️⃣ 索引设计原则

主键索引:自增ID或雪花ID 唯一索引:业务唯一键(如 short_code) 普通索引:高频查询字段(如 user_id、created_at) 复合索引:多条件查询(遵循最左前缀原则)

索引优化技巧:

--  错误:索引字段使用函数
SELECT * FROM url_mapping WHERE DATE(created_at) = '2024-01-01';

--  正确:直接使用索引字段
SELECT * FROM url_mapping
WHERE created_at >= '2024-01-01 00:00:00'
  AND created_at < '2024-01-02 00:00:00';

--  复合索引的最左前缀原则
-- 索引:(user_id, created_at)
-- 可以使用的查询:
SELECT * FROM url_mapping WHERE user_id = 123;  --  使用索引
SELECT * FROM url_mapping WHERE user_id = 123 AND created_at > '2024-01-01';  --  使用索引
SELECT * FROM url_mapping WHERE created_at > '2024-01-01';  --  不使用索引(违反最左前缀)

🏗️ 六、步骤5:架构设计(Architecture Design)

这是面试的核心部分,占30-40%的时间。

1️⃣ 架构演进三部曲

优秀的架构是演进出来的,不是一开始就设计得很复杂。

V1:单体架构(MVP)

先设计一个最简单可用的版本:

┌─────────────────────────────────────────────────────────────┐
│                       V1:单体架构                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌──────────┐                                               │
│  │ 客户端    │                                               │
│  └────┬─────┘                                               │
│       │ HTTP                                                │
│                                                            │
│  ┌─────────────┐                                            │
│  │  Web Server │                                            │
│  │  (Nginx)    │                                            │
│  └──────┬──────┘                                            │
│         │                                                   │
│                                                            │
│  ┌─────────────┐          ┌─────────────┐                  │
│  │ Application │  ─────→  │   MySQL     │                  │
│  │  (Go/Java)  │          │  (Master)   │                  │
│  └─────────────┘          └─────────────┘                  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

特点:
 简单易实现,快速上线
 单机部署,运维成本低
 性能瓶颈:数据库和应用都是单点
 可用性差:任何组件故障都会导致服务不可用

V2:读写分离 + 缓存

引入缓存和读写分离提升性能:

┌─────────────────────────────────────────────────────────────┐
│                  V2:读写分离 + 缓存                        │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌──────────┐                                               │
│  │ 客户端    │                                               │
│  └────┬─────┘                                               │
│       │                                                     │
│                                                            │
│  ┌─────────────┐                                            │
│  │Load Balancer│ (Nginx/LVS)                               │
│  └──────┬──────┘                                            │
│         │                                                   │
│         ├─────────┬─────────┬─────────┐                    │
│                                                        │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐                   │
│  │  App 1   │ │  App 2   │ │  App N   │                   │
│  └────┬─────┘ └────┬─────┘ └────┬─────┘                   │
│       │            │            │                          │
│       └────────┬───┴────────────┘                          │
│                │                                            │
│      ┌─────────┼─────────────┐                             │
│      │         │              │                             │
│                                                          │
│  ┌────────┐ ┌────────┐  ┌──────────┐                      │
│  │ Redis  │ │ MySQL  │  │  MySQL   │                      │
│  │(缓存)  │ │(Master)│  │ (Slave)  │                      │
│  └────────┘ └────────┘  └──────────┘                      │
│                │              │                             │
│                └──────────────┘ (主从复制)                  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

改进:
 引入Redis缓存,读性能提升10-100倍
 读写分离,主库写、从库读
 应用层水平扩展,负载均衡
 主库仍是单点,写能力有限
 缓存一致性问题

V3:分库分表 + 高可用

引入分库分表和高可用:

┌─────────────────────────────────────────────────────────────┐
│               V3:分库分表 + 高可用架构                      │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌──────────┐                                               │
│  │   CDN    │ (静态资源加速)                                │
│  └────┬─────┘                                               │
│       │                                                     │
│  ┌────┴───────────────┐                                    │
│  │  Load Balancer     │ (Nginx + Keepalived)              │
│  │  (主备高可用)       │                                    │
│  └────┬───────────────┘                                    │
│       │                                                     │
│       ├────────────────┬────────────────┐                  │
│                                                         │
│  ┌──────────┐    ┌──────────┐    ┌──────────┐             │
│  │ App集群  │    │ App集群   │    │ App集群   │             │
│  │ (机房A)  │    │ (机房B)   │    │ (机房C)   │             │
│  └────┬─────┘    └────┬─────┘    └────┬─────┘             │
│       │               │               │                    │
│  ┌────┴───────────────┴───────────────┴────┐               │
│  │            中间件层                      │               │
│  │  ┌────────────┐  ┌────────────┐         │               │
│  │  │ Redis集群  │  │   Kafka    │         │               │
│  │  │ (主从+哨兵) │  │ (消息队列)  │         │               │
│  │  └────────────┘  └────────────┘         │               │
│  └────┬───────────────────────────────────┘               │
│       │                                                     │
│  ┌────┴───────────────┬────────────────┐                  │
│  │    数据库层(分库分表)               │                  │
│  │  ┌──────────┐  ┌──────────┐  ┌──────────┐             │
│  │  │  DB Shard│  │  DB Shard│  │  DB Shard│             │
│  │  │     0    │  │     1    │  │     N    │             │
│  │  └────┬─────┘  └────┬─────┘  └────┬─────┘             │
│  │       │            │            │                      │
│  │   ┌───┴───┐    ┌───┴───┐    ┌───┴───┐                │
│  │   │ Slave │    │ Slave │    │ Slave │                │
│  │   └───────┘    └───────┘    └───────┘                │
│  └───────────────────────────────────────────────────────┘│
│                                                             │
└─────────────────────────────────────────────────────────────┘

改进:
 分库分表,突破单机写瓶颈
 多机房部署,容灾能力强
 Redis哨兵模式,缓存高可用
 Kafka异步化,削峰填谷
 支持千万级DAU

2️⃣ 架构图绘制技巧

标准符号:

□ 矩形:服务器、应用、数据库
○ 圆形:客户端、用户
◇ 菱形:决策点、网关
→ 箭头:数据流向(标注协议:HTTP、TCP、gRPC)
== 双线:主从复制、数据同步

分层原则:

从上到下:
1. 客户端层(Web、Mobile、API)
2. 接入层(CDN、DNS、负载均衡)
3. 应用层(Web服务器、业务服务)
4. 中间件层(缓存、消息队列)
5. 数据层(数据库、存储)

关键要素:

  • 标注每个组件的作用
  • 标注数据流向和协议
  • 标注关键的技术选型
  • 标注数据量和QPS

️ 七、步骤6:深入细节(Deep Dive)

这一步展示你的技术深度和工程经验。

1️⃣ 核心流程详解

选择1-2个核心流程,深入讲解实现细节。

示例:短链跳转流程

┌─────────────────────────────────────────────────────────────┐
│                 短链跳转流程(详细版)                       │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. 用户访问短链                                             │
│     GET https://short.ly/abc123                             │
│     │                                                       │
│                                                            │
│  2. Nginx接收请求                                           │
│     - 解析Host和Path                                        │
│     - 转发到应用服务器                                       │
│     │                                                       │
│                                                            │
│  3. 应用层处理                                              │
│     ┌─────────────────────────────────┐                    │
│     │ a. 查询Redis缓存                │                    │
│     │    key = "short:abc123"         │                    │
│     │    value = "https://long.url"   │                    │
│     │    TTL = 3600s                  │                    │
│     ├─────────────────────────────────┤                    │
│     │ b. 缓存未命中 → 查询MySQL       │                    │
│     │    SELECT long_url              │                    │
│     │    FROM url_mapping             │                    │
│     │    WHERE short_code = 'abc123'  │                    │
│     ├─────────────────────────────────┤                    │
│     │ c. 更新缓存                     │                    │
│     │    SET short:abc123 long_url    │                    │
│     │    EXPIRE 3600                  │                    │
│     ├─────────────────────────────────┤                    │
│     │ d. 异步更新点击量(Kafka)       │                    │
│     │    发送消息 → Kafka              │                    │
│     │    topic: url_click             │                    │
│     │    payload: {short_code, ts}    │                    │
│     └─────────────────────────────────┘                    │
│     │                                                       │
│                                                            │
│  4. 返回302重定向                                           │
│     HTTP/1.1 302 Found                                     │
│     Location: https://long.url                             │
│     │                                                       │
│                                                            │
│  5. 浏览器自动跳转到长链接                                   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

2️⃣ 技术选型与权衡(Trade-off)

面试官喜欢问:"为什么选XXX,而不是YYY?"

你需要展示权衡分析能力:

示例:缓存选型

方案优点缺点适用场景
Redis性能极高(10万QPS)、数据结构丰富、持久化内存成本高、数据量有限热点数据、高频访问
Memcached简单、性能高、多线程无持久化、数据结构单一纯缓存场景
本地缓存无网络开销、性能最高数据不共享、缓存不一致静态数据、配置

权衡因素:

  • 性能:Redis 10万QPS vs MySQL 1万QPS
  • 成本:Redis内存贵 vs MySQL磁盘便宜
  • 一致性:Redis最终一致 vs MySQL强一致
  • 可用性:Redis高可用(哨兵)vs MySQL主从
  • 功能:Redis数据结构丰富 vs MySQL SQL强大

结论:

选择Redis的原因:
1. 短链跳转是高频操作(3000 QPS),需要极致性能
2. 数据量小(几百GB),适合Redis
3. 允许最终一致性(缓存失效最多查一次DB)
4. 支持TTL,自动过期

3️⃣ 性能优化方案

常见优化点:

A. 缓存优化

1. 多级缓存
   Browser Cache → CDN → Redis → MySQL

2. 缓存预热
   系统启动时,预加载热点数据

3. 缓存穿透
   布隆过滤器 → 拦截不存在的key

4. 缓存击穿
   热点key加互斥锁,避免并发查DB

5. 缓存雪崩
   过期时间加随机值,避免同时失效

B. 数据库优化

1. 索引优化
   - 覆盖索引:SELECT时只查索引列
   - 联合索引:遵循最左前缀原则

2. 查询优化
   - 避免SELECT *
   - 使用LIMIT分页
   - 避免子查询,改用JOIN

3. 分库分表
   - 垂直拆分:按业务拆表
   - 水平拆分:按Hash/Range分表

4. 读写分离
   - 主库写、从库读
   - 延迟监控(主从延迟<1s)

C. 异步化改造

同步 → 异步:
1. 点击量统计:同步更新DB → 异步消息队列
2. 日志记录:同步写文件 → 异步批量写入
3. 通知推送:同步调用API → 异步任务队列

八、步骤7:总结收尾(Wrap Up)

最后3-5分钟,快速回顾设计,查漏补缺。

1️⃣ 回顾核心设计

简要总结:
1. 需求:支持1000万DAU,峰值3500 QPS
2. 架构:读写分离 + Redis缓存 + 异步统计
3. 优化:布隆过滤器防穿透,分库分表支持扩展
4. 监控:QPS、延迟、缓存命中率

2️⃣ 讨论未覆盖的点

主动提出可扩展的方向:

如果时间充足,我们还可以讨论:
1. 短链防刷:限流、风控、验证码
2. 自定义短链:冲突检测、敏感词过滤
3. 数据分析:BI报表、漏斗分析
4. 国际化:多地域部署、就近访问

3️⃣ 回答追问

面试官可能的追问:

追问回答思路
"如何防止短链被恶意刷?"限流(令牌桶)+ 风控(IP黑名单)+ 验证码
"缓存和DB数据不一致怎么办?"允许短暂不一致 + 缓存失效 + 定期对账
"单机Redis扛不住怎么办?"Redis Cluster分片 + 客户端分片 + Proxy分片
"如何支持自定义短链?"唯一性检查 + 敏感词过滤 + 付费功能

九、面试技巧与常见错误

1️⃣ 黄金法则

DO:

1. 澄清需求:不要假设,主动提问
2. 从简单开始:先MVP,再优化
3. 展示思考过程:说出你的推理
4. 画清晰的图:用标准符号,逻辑清晰
5. 讨论权衡:没有完美方案,只有合适的
6. 保持沟通:不要闷头设计,边画边讲
7. 举真实案例:"我在XX公司做过类似系统"

DON'T:

1. 不要一开始就设计复杂架构
2. 不要忽略非功能需求(性能、可用性)
3. 不要假设面试官知道你在想什么(要讲出来)
4. 不要纠结完美方案(时间有限,先完成核心)
5. 不要死记硬背(面试官会追问细节)
6. 不要说"我不知道"(可以说"我的理解是...")

2️⃣ 常见错误

错误后果正确做法
一开始就设计分布式系统过度设计,浪费时间先单体MVP,再演进
容量估算错误架构设计不合理记住常用数字,公式推导
画架构图太乱面试官看不懂用标准符号,分层清晰
只讲技术,不讲权衡缺少深度思考对比多个方案优缺点
忽略监控告警不够生产级别主动提出监控指标

3️⃣ 时间管理技巧

45分钟面试的时间分配:
┌────────────────────────────────────────┐
│ 0-5min:  需求澄清(问清楚要做什么)      │
│ 5-10min: 容量估算(QPS、存储、带宽)     │
│ 10-15min: 接口和数据模型(可选)         │
│ 15-35min: 架构设计(核心,画图+讲解)    │
│ 35-40min: 深入细节(技术选型、优化)     │
│ 40-45min: 总结收尾(查漏补缺)          │
└────────────────────────────────────────┘

如果时间不够:
- 跳过接口设计(直接说"API遵循RESTful规范")
- 简化数据模型(只讲核心表)
- 重点在架构图和核心流程

十、学习资源与练习

1️⃣ 推荐书籍

  • 《System Design Interview》- Alex Xu()
  • 《Designing Data-Intensive Applications》- Martin Kleppmann
  • 《微服务架构设计模式》- Chris Richardson

2️⃣ 在线资源

  • System Design Primer - GitHub 170k stars
  • Grokking the System Design Interview
  • ByteByteGo - Alex Xu的系统设计课程

3️⃣ 练习方法

阶段1:学习方法论(1周)

- 通读本章,理解完整流程
- 记住常用数字(QPS、存储、带宽)
- 学习画架构图的标准符号

阶段2:刷经典案例(2-4周)

- 每天1个案例,从简单到复杂
- 先看题目,自己设计30分钟
- 再看答案,对比差距
- 重点案例多刷几遍

阶段3:模拟面试(1-2周)

- 找朋友模拟面试,限时45分钟
- 录屏回放,找出问题
- 重点训练讲解能力

Prev
系统设计面试教程
Next
01-短链系统设计