系统设计图把架构决策转化成一种工程师、产品经理和利益相关方都能共同阅读的视觉语言。无论你是在备战技术面试、记录现有系统,还是规划新项目,能画出清晰的系统设计图都是一项基础的工程技能。
这篇指南覆盖系统设计图需要的核心组件、如何从零开始结构化地画一张,以及三个经典架构的拆解走查。
为什么图表在系统设计中很重要
用文字描述系统设计本质上是模糊的。「该服务从数据库读取」——哪个服务?哪个数据库?这是同步的吗?中间先过缓存吗?
图表让这些关系变得明确。每条箭头是一条数据流。每个方框是一个组件。连接上的每个标签是一个协议或契约。没有任何空间容纳那种让团队在澄清会议上浪费数小时或因为实现错误浪费数周的模糊性。
图表也是系统设计面试的评估方式。一边讲一边画、让数据流可见、让扩展决策显式的候选人,远比纯粹用语言解释架构的人更容易评估。
系统设计图的核心组件
无论规模或领域,大多数系统都由同一套基础构建块组成:
客户端
进入系统的入口点,通常是:
- 通过 HTTP 访问的浏览器
- 使用 REST 或 GraphQL API 的移动应用(iOS、Android)
- 编程方式调用 API 的第三方服务
- 调用你的 API 的内部服务
把客户端画为图表左侧(或顶部)的方框,从客户端出发的箭头指向你的系统。
负载均衡器和 API 网关
接收所有传入请求并将它们路由到合适服务的层。负载均衡器将流量分发到同一服务的多个实例上。API 网关还处理鉴权、限流和请求转换。
常见实例:Nginx、AWS ALB、AWS API Gateway、Cloudflare。
在图表中,负载均衡器位于客户端层之后、应用服务之前。
应用服务
业务逻辑层。简单应用可能只有一个服务,较大的系统通常是多个微服务,每个负责特定领域(用户服务、支付服务、通知服务)。
画服务时:
- 根据功能给每个服务一个清晰的名称
- 展示哪些服务相互通信
- 在箭头上标注通信方式(REST、gRPC、消息队列)
数据库和存储
每个系统都要在某处存储数据。图表中需要展示的关键区别:
- SQL 数据库(PostgreSQL、MySQL):结构化数据、强一致性、复杂查询
- NoSQL 数据库(DynamoDB、MongoDB、Cassandra):灵活 schema、水平扩展、最终一致性
- 缓存(Redis、Memcached):快速读取、临时数据,位于数据库前面
- 对象存储(S3):文件、图片、视频、大型二进制数据
- 消息队列(Kafka、RabbitMQ、SQS):服务间异步通信
数据库画为圆柱体,缓存用不同标签的圆柱体,对象存储用独立的方框。
CDN
内容分发网络把静态资源(图片、CSS、JavaScript、视频)缓存在靠近用户的边缘服务器上,降低延迟并减少源服务器的负载。把 CDN 画在客户端和源存储或服务器之间。
外部服务
第三方依赖:支付处理(Stripe)、邮件提供商(SendGrid)、短信网关(Twilio)、推送通知服务、分析平台。把这些画在图表边缘,箭头标注调用方向。
如何画系统设计图
从高层开始。 先画 5-6 个主要组件。第一遍不要试图展示每个微服务、每个数据库表或每个边缘情况。先把宏观结构做对。
用箭头展示数据流。 箭头代表数据在系统中流动,箭头指向表示方向。双向箭头表示通信是双向的。始终在箭头上标注正在通信的内容或使用的协议。
把相关组件分组。 用框架、虚线边框或颜色编码来展示哪些组件属于同一领域或服务边界,让什么在你系统内、什么是外部的一目了然。
标注所有内容。 服务名称、数据库类型、协议和关键决策都应该标注。「Service」和「DB」不是有用的标注。「用户服务」和「PostgreSQL(用户表)」才是。
按层次思考。 一张画得好的系统设计图从左到右(或从上到下)流经逻辑层:客户端 → 负载均衡器 → 应用服务 → 数据库 → 外部服务。
案例一:URL 短链服务
URL 短链(如 bit.ly)是经典的系统设计题。核心行为:用户提交一个长 URL 得到一个短码;另一个用户访问短 URL 被重定向到长 URL。
组件:
- 客户端:浏览器或 API 调用方
- 负载均衡器:将流量分发到 API 服务器
- 短链服务:处理创建和重定向请求
- 数据库(SQL):存储短码 → 长 URL 的映射
- 缓存(Redis):存储高频访问的映射,加速重定向
- 分析服务:异步记录点击数据
- 消息队列:将分析写入与重定向响应解耦
数据流:
- 创建:客户端 → LB → 服务 → DB(写入映射)→ 返回短 URL
- 重定向:客户端 → LB → 服务 → 缓存(命中?直接重定向)→ DB(未命中?读取、缓存、重定向)→ 分析(通过队列异步)
缓存是关键:重定向的频率远高于创建,缓存命中避免了每次重定向都读数据库。
案例二:聊天应用
实时聊天系统(如微信、Slack)需要持久连接,而不只是请求-响应。
组件:
- 客户端:移动或 Web 应用
- WebSocket 网关:维护用于实时消息传递的持久连接
- 聊天服务:管理频道,投递消息
- 在线状态服务:追踪在线/离线状态
- 数据库(NoSQL,如 Cassandra):存储消息历史(写密集、按时间排序)
- 缓存(Redis):存储活跃会话数据和最近消息
- 消息队列(Kafka):向多个接收者扇出投递
- 通知服务:处理离线用户的推送通知
- 对象存储(S3):存储图片和文件附件
- CDN:提供媒体文件
需要展示的关键设计决策:
- WebSocket 连接用于实时投递(不是轮询)
- NoSQL 数据库用于消息存储(时间序列访问模式、写密集)
- 通过队列扇出:当消息发送到群组,队列将其分发到所有成员会话
案例三:社交媒体信息流
信息流(如微博、Instagram 的首页)涉及两个核心难题:高效生成信息流和大规模投递。
组件:
- 客户端:移动或 Web 应用
- API 网关 / 负载均衡器
- 信息流服务:提供用户的信息流
- 帖子服务:处理发布新帖子
- 用户服务:管理关注和被关注关系
- 扇出服务:将新帖子分发到关注者的信息流
- 信息流缓存(Redis):每个用户预计算好的信息流(快速读取)
- 帖子数据库(NoSQL):存储帖子内容
- 社交图谱数据库(图数据库或 SQL):存储关注关系
- 媒体存储(S3 + CDN):存储并提供图片和视频
两种信息流方案(值得在图表中展示权衡):
推模式(写时扇出): 用户发帖时,立即写入每个关注者的信息流缓存。读取快速,粉丝百万的用户写入开销极大。
拉模式(读时扇出): 用户打开应用时,从关注的所有人那里拉取最近的帖子来计算信息流。读取慢,没有写入开销。
混合模式: 普通用户推模式,百万粉丝的大 V 拉模式。大多数真实系统使用这种方式。
系统设计图的常见错误
没有数据流方向。 没有箭头的线,或者方向错误的箭头,会造成数据实际如何移动的混乱。
缺少缓存。 大多数处理大量读取流量的系统在数据库前面使用缓存。如果图表里没有,看起来像是设计上的漏洞。
只有正常路径。 真实的系统设计要考虑失败情况:数据库不可用时怎么办?缓存冷启动时怎么办?这些不是可选的考虑。
试图展示所有内容。 展示每个接口、每个字段和每种可能状态的图表是无法阅读的。在适合你受众的抽象层次画图。
箭头上没有标注。「有某些数据在这里流动」不是系统设计。在每条箭头上标注正在传输什么或使用的协议。
开始练习
如果想动手实践,可以尝试自己画上面的架构。CodePic 提供了系统设计模板,包含预制的客户端、服务、数据库、缓存和队列组件。如果你要画微服务架构图,微服务模板包含服务边界、API 网关和服务间通信模式。



