经典系统设计 — AI 时代的架构师认知地图

3 阅读14分钟

AI 能写代码,但"这个系统该怎么拆、数据怎么流、瓶颈在哪里"必须你来判断。 这份文档覆盖主流系统的核心设计思路,建立系统思维的基础。

不追求每个系统的完整设计,而是抓住每个系统最核心的设计挑战和解法。

目录


一、电商系统

电商是系统设计的集大成者,几乎涵盖所有核心问题。

1.1 商品系统

核心挑战: 读多写少,SKU 数量巨大,需要多维度搜索。

架构:

写入: 运营后台 → MySQL(主库)→ 同步到 ES + Redis
读取: 商品列表/搜索 → Elasticsearch
      商品详情 → Redis 缓存 → 缓存未命中 → MySQL

技术选型:

组件选型理由
主存储MySQL商品数据需要事务(上下架、价格变更)
搜索Elasticsearch多维度搜索(品类、价格区间、关键词)
缓存Redis商品详情页 QPS 极高,必须缓存

关键概念:

  • 读写分离:写 MySQL,读 ES + Redis
  • 数据同步:MySQL → ES 用 Canal(binlog 监听),MySQL → Redis 用 Cache Aside 模式
  • SPU / SKU 模型:SPU 是商品(iPhone 16),SKU 是具体规格(iPhone 16 黑色 256G)

1.2 购物车

核心挑战: 登录/未登录状态合并,高频读写。

架构:

未登录: 购物车存浏览器 localStorage
登录后: localStorage 数据合并到服务端
服务端: Redis Hash 存储(key=userId, field=skuId, value=数量)

为什么用 Redis 不用 MySQL:

  • 购物车是高频读写(用户频繁加减商品)
  • 不需要复杂查询
  • Redis Hash 天然适合这个数据结构
  • 持久化:Redis RDB/AOF + 定期同步到 MySQL 兜底

关键概念:

  • 登录态合并:未登录加了 3 件,登录后要合并到账号下
  • 购物车上限:防止恶意用户加几万件商品
  • 价格实时性:展示时要查最新价格,不能用加入时的价格

1.3 订单系统

核心挑战: 数据一致性、状态机、高并发下单。

状态机:

待支付 → 已支付 → 待发货 → 已发货 → 已收货 → 已完成
  ↓         ↓
已取消    已退款

架构:

下单: 前端 → 订单服务 → 创建订单(MySQL)→ 发 MQ → 库存服务扣减
支付: 支付回调 → 订单服务更新状态 → 发 MQ → 通知/物流

技术选型:

组件选型理由
主存储MySQL订单需要强一致性和事务
订单号雪花算法 / 分布式 ID全局唯一、有序、不可猜测
状态流转MQ解耦订单和下游(库存、支付、物流)

关键概念:

  • 幂等性:支付回调可能重复,用订单号去重
  • 超时取消:待支付订单 30 分钟未支付自动取消(延迟队列 / 定时任务)
  • 分库分表:订单量大了按 userId 分表

1.4 支付系统

核心挑战: 钱不能多不能少,必须强一致。

核心流程:

用户点支付 → 创建支付单 → 调第三方支付(微信/支付宝)→ 等待回调
第三方回调 → 验签 → 更新支付单状态 → 更新订单状态

关键概念:

  • 幂等性:回调可能重复,必须用支付单号去重
  • 对账:每天和第三方对账,发现差异人工处理
  • 退款:退款是独立流程,不是支付的逆操作
  • 掉单处理:回调没收到怎么办?定时轮询第三方查询接口

安全:

  • 回调验签:确认回调确实来自第三方,不是伪造的
  • 金额校验:回调金额必须和订单金额一致
  • HTTPS:所有支付相关通信必须加密

1.5 库存系统

核心挑战: 超卖问题——100 件库存,200 人同时下单。

方案对比:

方案原理优缺点
数据库乐观锁UPDATE SET stock=stock-1 WHERE stock>0简单,但高并发下大量失败重试
Redis 预扣减DECR stock,原子操作快,但 Redis 和 DB 可能不一致
分布式锁加锁 → 扣减 → 释放安全,但性能差

标准方案: Redis 预扣减 + MQ 异步落库

下单 → Redis DECR(原子操作,不会超卖)→ 返回成功
    → MQ → 库存服务 → MySQL UPDATE

二、社交 / 内容平台

2.1 Feed 流(朋友圈 / 小红书 / Instagram)

核心挑战: 用户打开首页,看到关注的人发的内容,按时间排序。怎么高效生成这个列表?

两种模式:

模式原理适用场景
推模式(写扩散)发布时推送到所有粉丝的收件箱粉丝少(朋友圈)
拉模式(读扩散)读取时从所有关注人的发件箱拉取合并粉丝多(微博大V)
推拉结合普通用户推,大V拉大规模社交平台

推模式架构:

用户 A 发帖 → 写入 A 的发件箱(MySQL)
           → 查 A 的粉丝列表
           → 写入每个粉丝的收件箱(Redis Sorted Set,score=时间戳)

用户 B 刷 Feed → 读 B 的收件箱(Redis ZREVRANGE)→ 分页返回

技术选型:

  • 收件箱:Redis Sorted Set(按时间排序,分页查询 O(logN))
  • 发件箱:MySQL(持久化,支持查看"我的发布")
  • 内容存储:MySQL + 对象存储(图片/视频)

关键概念:

  • 写扩散的成本:一个有 100 万粉丝的大V发一条,要写 100 万次
  • Timeline vs Rank Feed:按时间排序 vs 按算法推荐排序
  • 游标分页:用 lastId 而不是 offset,避免翻页时数据偏移

2.2 评论系统

核心挑战: 树形结构(评论的回复的回复),高效查询和分页。

数据模型:

comments (
  id, content, user_id,
  parent_id,     -- 直接父评论(NULL 表示一级评论)
  root_id,       -- 根评论 ID(用于查询某条评论的所有回复)
  target_id,     -- 被评论的对象(帖子/商品)
  created_at
)

查询策略:

一级评论: WHERE target_id=? AND parent_id IS NULL ORDER BY created_at LIMIT 20
二级回复: WHERE root_id=? ORDER BY created_at LIMIT 10

为什么不用邻接表递归查询: 深层嵌套递归查询性能差。用 root_id 扁平化,前端自己组装树形结构。

技术选型:

  • 存储:MySQL(需要事务,评论数不算特别大)
  • 计数:Redis(评论数缓存,避免 COUNT 查询)
  • 敏感词过滤:前置过滤服务

2.3 点赞 / 收藏 / 关注

核心挑战: 高频操作,需要快速判断"我是否已点赞"。

架构:

点赞: Redis SETkey=post:123:likes, value=userId)
     → 异步 MQ → MySQL 持久化
查询"我是否点赞": Redis SISMEMBER O(1)
查询"点赞数": Redis SCARD 或单独计数器

为什么不直接用 MySQL:

  • "我是否点赞"是每次渲染都要查的,QPS 极高
  • MySQL 每次 SELECT WHERE post_id=? AND user_id=? 太慢
  • Redis SET 的 SISMEMBER 是 O(1)

关键概念:

  • 计数器:单独维护,不要每次 COUNT
  • 取消点赞:SREM + 计数器 DECR
  • 数据一致性:Redis 和 MySQL 最终一致,不需要强一致

三、即时通讯(IM)

核心挑战: 实时性、消息可靠投递、离线消息、群聊扩散。

架构:

客户端 A ←→ WebSocket ←→ Gateway → MQ → 消息服务 → 存储
                                              ↓
客户端 B ←→ WebSocket ←→ Gateway ← 推送 ←──┘

技术选型:

组件选型理由
长连接WebSocket全双工,实时推送
网关自研 / Netty维护百万级长连接
消息存储MySQL + HBase近期消息 MySQL,历史消息 HBase
消息队列Kafka群聊消息扩散、异步投递
推送APNs / FCM离线推送

关键概念:

  • 消息 ID:全局有序(雪花算法),用于排序和去重
  • 已读回执:客户端上报已读的最大消息 ID
  • 离线消息:用户上线后拉取离线期间的消息(收件箱模式)
  • 群聊扩散:写扩散(小群)vs 读扩散(大群)
  • 消息漫游:多端同步,换设备能看到历史消息

难点:

  • 百万级长连接管理(单机 10 万连接,需要多台 Gateway)
  • 消息的有序性(同一个会话内消息必须有序)
  • 多端同步(手机、电脑、平板同时在线)

四、视频平台(YouTube / B站)

核心挑战: 大文件存储、转码、CDN 分发、推荐算法。

上传 → 播放全链路:

上传: 客户端分片上传 → 对象存储(原始文件)
      → MQ → 转码服务(多分辨率:1080p/720p/480p)
      → 转码完成 → 对象存储(转码后文件)→ CDN 预热

播放: 客户端请求 → CDN 边缘节点(命中缓存直接返回)
      → CDN 未命中 → 回源到对象存储
      → 自适应码率(根据网络质量切换分辨率)

技术选型:

组件选型理由
存储S3 / OSS海量视频文件
转码FFmpeg 集群CPU 密集型,需要水平扩展
分发CDN全球加速,减少延迟
播放协议HLS / DASH自适应码率,分片加载
推荐协同过滤 + 深度学习个性化推荐

关键概念:

  • HLS(HTTP Live Streaming):视频切成小片段(.ts),按需加载
  • 自适应码率:网络好播 1080p,网络差自动降到 480p
  • 预加载:播放当前片段时预加载下一个片段
  • 冷热分离:热门视频放 CDN,冷门视频放对象存储

五、直播系统

核心挑战: 超低延迟(< 3 秒)、高并发观看、弹幕实时同步。

架构:

主播推流 → RTMP → 流媒体服务器 → 转码(多码率)
                                    ↓
观众拉流 ← CDN ← HLS/FLV ← 流媒体服务器

弹幕: 观众发送 → WebSocket → 弹幕服务 → 广播给同房间所有观众

协议选择:

协议延迟适用场景
RTMP1-3 秒推流端(主播)
HLS5-30 秒大规模分发(CDN 友好)
HTTP-FLV1-3 秒低延迟拉流
WebRTC< 1 秒连麦、视频通话

关键概念:

  • 推流 vs 拉流:主播推,观众拉
  • 房间模型:每个直播间是一个"房间",弹幕只在房间内广播
  • 连麦:WebRTC P2P 或通过服务器中转
  • 礼物系统:本质是支付系统 + 动画渲染

六、云文档(飞书文档 / Google Docs)

核心挑战: 多人实时协同编辑,冲突解决。

两种协同算法:

算法原理代表产品
OT(Operational Transformation)操作转换,服务端协调Google Docs
CRDT(Conflict-free Replicated Data Type)无冲突数据结构,去中心化Figma、Yjs

OT 简单理解:

用户 A 在位置 3 插入 "X"
用户 B 在位置 1 插入 "Y"
→ 服务端收到 A 的操作后,转换 B 的操作:位置 1 → 还是 1(在 A 插入点之前)
→ 服务端收到 B 的操作后,转换 A 的操作:位置 3 → 变成 4B 在前面插入了一个字符)

架构:

客户端 A ←→ WebSocket ←→ 协同服务(OT/CRDT)←→ WebSocket ←→ 客户端 B
                              ↓
                         文档存储(快照 + 操作日志)

技术选型:

组件选型理由
通信WebSocket实时双向同步
协同算法OT 或 CRDT冲突解决
存储快照 + Op Log快照用于加载,Op Log 用于回放和协同
富文本模型Slate / ProseMirror / 自研结构化文档模型

关键概念:

  • 操作日志(Op Log):记录每一次编辑操作,可以回放
  • 快照(Snapshot):定期保存文档完整状态,加速加载
  • 光标同步:其他人的光标位置实时显示
  • 离线编辑:离线时本地编辑,上线后合并(CRDT 更擅长)

七、项目管理(Jira / Linear)

核心挑战: 灵活的数据模型(不同团队的工作流不同)、权限控制、实时协作。

数据模型:

Workspace → Project → Board → Column → Issue
                                         ↓
                                    Comment / Attachment / Activity Log

关键设计:

  • 自定义字段:Issue 的字段不固定(有的团队要"优先级",有的要"故事点")→ EAV 模型或 JSON 字段
  • 工作流引擎:每个 Board 的列(Column)代表状态,拖拽 = 状态流转,可自定义
  • 权限模型:RBAC(角色:Admin / Member / Viewer)+ 项目级权限
  • 活动日志:所有操作记录(谁在什么时候改了什么),用于审计和通知

技术选型:

组件选型理由
主存储PostgreSQL支持 JSONB(灵活字段)、全文搜索
实时更新WebSocket / SSE看板拖拽实时同步
搜索PostgreSQL 全文搜索 或 ES数据量不大时 PG 够用
文件S3附件存储

八、搜索系统

核心挑战: 海量数据中毫秒级返回相关结果。

架构:

数据写入 → MySQL → Canal(binlog 监听)→ Elasticsearch
搜索请求 → API → Elasticsearch → 返回结果

Elasticsearch 核心概念:

  • 倒排索引:传统数据库是"文档 → 词",ES 是"词 → 文档列表"
  • 分词器:中文用 IK 分词,英文用标准分词
  • 相关性评分:TF-IDF / BM25,决定结果排序
  • 分片:数据水平拆分到多个节点

搜索优化:

  • 搜索建议(Suggest):用户输入时实时提示
  • 拼写纠错:"iphoen" → "iphone"
  • 同义词:搜"手机"也能搜到"电话"
  • 热搜:Redis 计数器统计搜索频率

九、通知系统

核心挑战: 多渠道(站内信、推送、邮件、短信)、不重复、不遗漏。

架构:

业务事件 → MQ → 通知服务 → 路由(根据用户偏好选择渠道)
                              ├→ 站内信 → MySQL + WebSocket 推送
                              ├→ App 推送 → APNs / FCM
                              ├→ 邮件 → SMTP 服务
                              └→ 短信 → 短信网关

关键概念:

  • 通知模板:不同事件用不同模板("{{user}} 评论了你的帖子")
  • 聚合通知:"张三等 5 人赞了你的帖子"(不是发 5 条通知)
  • 用户偏好:用户可以关闭某类通知
  • 限流:防止通知轰炸(同一用户同一类型 1 小时最多 N 条)
  • 已读管理:标记已读、全部已读

十、文件存储与 CDN

核心挑战: 海量文件的存储、分发、访问控制。

架构分层:

上传: 客户端 → Presigned URL → 对象存储(S3)
访问: 客户端 → CDN(边缘缓存)→ 对象存储(回源)
管理: 后端 → 对象存储 SDK(删除、移动、权限)

存储选型:

场景选型理由
用户上传的图片/视频对象存储(S3)海量、低成本、高可用
需要文件系统语义分布式文件系统(JuiceFS)POSIX 接口,可挂载
临时文件本地磁盘 / tmpfs处理完就删
静态资源(JS/CSS)CDN全球加速

关键概念:

  • Presigned URL:后端生成签名 URL,前端直传,后端不承受流量
  • CDN 缓存策略:Cache-Control、ETag、缓存刷新
  • 图片处理:对象存储通常支持 URL 参数裁剪/压缩(?w=200&h=200
  • 冷热分离:热数据标准存储,冷数据归档存储(成本低 10 倍)
  • 生命周期策略:自动删除 N 天前的临时文件

附:系统设计万能框架

面试时拿到任何系统设计题,都可以用这个框架:

Step 1: 需求澄清(2 分钟)

  • 核心功能是什么?(不要试图设计所有功能)
  • 用户量级?QPS?数据量?
  • 读多还是写多?
  • 一致性要求?(强一致 vs 最终一致)
  • 延迟要求?(实时 vs 秒级 vs 分钟级)

Step 2: 高层架构(5 分钟)

  • 画出核心组件和数据流
  • 确定同步/异步边界
  • 确定存储选型

Step 3: 核心设计(15 分钟)

  • 数据模型(表结构 / Schema)
  • API 设计(核心接口)
  • 最难的那个问题怎么解(每个系统都有一个核心难点)

Step 4: 扩展与优化(5 分钟)

  • 瓶颈在哪里?怎么扩展?
  • 缓存加在哪一层?
  • 如果数据量增长 10 倍怎么办?

每个系统的核心难点速查

系统核心难点
电商-订单分布式事务(下单扣库存扣余额)
电商-库存超卖(高并发扣减)
电商-支付幂等性 + 对账
Feed 流推拉模式选择 + 大V扩散
评论树形结构高效查询
IM消息有序性 + 百万级长连接
视频转码 + CDN 分发 + 自适应码率
直播超低延迟 + 弹幕广播
云文档协同冲突解决(OT/CRDT)
项目管理灵活数据模型 + 自定义工作流
搜索倒排索引 + 相关性排序
通知多渠道路由 + 聚合 + 限流