1. 为什么一张“架构流程图”值得单独拿出来讲
很多人第一次听到“架构流程图”这五个字,第一反应是:不就是画个框框图吗,Visio 拖几个方块、连几条线,半小时搞定。我刚开始做项目的时候也是这么想的,直到有一次给一个跨团队的系统做评审,我拿着自己画的“架构图”讲了二十分钟,台下一位资深工程师问了一句:“你这个箭头代表的是数据流还是调用关系?这条虚线是异步还是同步?”我当时就卡住了——因为我自己也没想清楚。
这件事之后我才明白,架构流程图不是美术作品,而是一种精确的沟通工具。它要回答的核心问题只有几个:系统由哪些部分组成、这些部分之间怎么交互、数据往哪里流、边界在哪里、出问题的时候责任落在谁头上。一张好的架构流程图,能让新加入的同事在十分钟内理解系统全貌,能让运维在半夜排障时快速定位到故障域,也能让产品经理看懂“为什么这个需求要改三个服务”。
这篇文章适合几类人看:刚接手一个陌生系统、需要快速梳理现状的开发者;准备做技术方案评审、需要把设计讲清楚的架构师;还有那些画了图却被吐槽“看不懂”的同学。我会从为什么要画、画之前想清楚什么、怎么分层画、常见符号怎么用、工具怎么选、评审时怎么讲这几个角度,把“架构流程图”这件事拆透。全程都是我自己踩过坑之后总结的实操经验,不是教科书式的定义罗列。
先给一个我自己的判断标准:如果一张架构图拿掉所有文字说明,一个没参与过项目的人还能大致说出系统的数据流向和主要模块,那这张图就及格了。后面所有的技巧,都是围绕这个标准展开的。
2. 画图之前必须先想清楚的四个问题
2.1 这张图是给谁看的,决定了它的抽象层级
我见过最常见的错误,就是一张图想同时满足所有人。给老板看的图里塞满了 Redis 集群分片细节,给运维看的图里又只有“业务层、服务层、数据层”三个大框。结果两边都不满意。
正确的做法是先定读者,再定粒度。我一般把架构流程图分成三个层级来画:
| 层级 | 读者 | 关注点 | 粒度示例 |
|---|---|---|---|
| 系统上下文图 | 老板、产品、外部团队 | 系统边界、外部依赖 | 本系统 vs 支付系统 vs 用户端 |
| 容器/服务图 | 架构师、开发、测试 | 服务划分、调用关系 | 订单服务、库存服务、网关 |
| 组件/部署图 | 运维、SRE、核心开发 | 进程、端口、中间件 | Nginx、Tomcat、MySQL 主从 |
我自己的习惯是:任何一次评审,至少准备上下文图和服务图两张。上下文图用来对齐“我们在做什么”,服务图用来讨论“怎么做”。如果评审涉及部署和容量,再加一张部署图。千万不要指望一张图打天下。
这里有个经验:给非技术同学讲的时候,上下文图里的框不要超过 7 个。超过 7 个,人的短期记忆就装不下了,他们会开始走神。如果外部依赖确实很多,就做聚合,比如把“短信、邮件、推送”合并成一个“消息通道”。
2.2 先明确“画的是什么流”,别把数据流和控制流混在一起
这是我在评审里被问倒的那次之后,痛定思痛总结出来的。架构流程图里其实混着好几种“流”:
- 数据流:数据从 A 传到 B,比如用户下单请求从网关到订单服务。
- 控制流:谁调用谁,比如订单服务调用库存服务扣减库存。
- 依赖流:编译期或部署期的依赖,比如服务 A 依赖服务 B 的 SDK。
- 部署流:进程部署在哪台机器、哪个机房。
这几种流如果画在同一张图里,用同一种箭头,必然混乱。我的做法是:一张图只突出一种主流,其他流用不同线型或颜色弱化。比如主图画数据流,用实线粗箭头;控制流用细实线;异步消息用虚线;部署关系干脆不画,放到另一张图。
提示:如果你发现一张图里箭头类型超过三种,基本可以判定这张图需要拆了。读者的认知负担已经过载。
2.3 边界要画出来,否则责任永远扯不清
架构图里最容易被忽略、但最重要的元素是边界。系统边界、团队边界、信任边界、故障边界,这些不画出来,出了问题就是互相甩锅。
我习惯用不同颜色的背景框来表示边界。比如:
- 蓝色背景:本团队负责的服务
- 灰色背景:其他团队负责的服务
- 红色虚线框:外部第三方系统
- 黄色背景:需要重点关注的故障域
有一次我们排查一个超时问题,就是因为架构图上没画清楚“这个缓存是跨机房共享的还是本机房独享的”,导致两个团队各自以为是对方的问题,查了一整天才发现是缓存穿透。后来我在图上专门加了一条注释:“本机房独享,不跨机房同步”。就这么一句话,省了后面无数次扯皮。
2.4 图例和注释不是可选项,是必选项
我见过太多图,箭头没有图例,框没有说明,颜色全靠猜。这种图发到群里,下面必然跟着一串“这个绿色是什么意思”“这条虚线是啥”。
我的硬性要求是:任何一张要发出去的架构图,必须带图例。图例至少包含:
- 框的形状含义(矩形=服务,圆柱=数据库,圆角矩形=外部系统)
- 线的类型含义(实线=同步调用,虚线=异步消息,点线=依赖)
- 颜色的含义(如果有颜色区分)
- 关键缩写的全称(比如 MQ、LB、GW)
注释方面,我会在关键路径上标注协议和端口,比如HTTP:8080、gRPC:9090、TCP:6379。别小看这个,排障的时候能省很多事。还有数据量级,比如“日均 100 万条”,这能帮助读者判断这个链路的压力等级。
3. 从零画一张架构流程图的完整实操链路
3.1 第一步:用白纸或白板做“信息倾倒”,别急着开工具
我强烈建议不要在还没想清楚的时候打开画图工具。工具会诱导你去调对齐、调颜色,反而干扰思考。我的做法是拿一张 A3 白纸,或者会议室白板,先把所有能想到的模块、系统、中间件、外部依赖全部写下来,不管顺序,不管层级,先倒出来。
这个阶段的目标是穷举,不是整理。比如我会写下:网关、用户服务、订单服务、库存服务、支付回调、消息队列、Redis、MySQL、配置中心、日志收集、监控告警、第三方支付、短信通道……写完之后,再开始归类。
归类的时候问自己三个问题:
- 哪些是我方能控制的,哪些是外部依赖?
- 哪些是同步链路,哪些是异步链路?
- 哪些是核心链路(挂了就影响主流程),哪些是旁路(挂了只影响体验)?
这三个问题的答案,直接决定了图上的布局和视觉权重。核心链路放中间、用粗线;旁路放边上、用细线;外部依赖用不同颜色标出来。
3.2 第二步:确定布局方向,从左到右还是从上到下
布局方向看起来是小事,其实影响很大。我的经验是:
- 数据流图用从左到右:符合阅读习惯,用户请求从左边进来,数据往右边流。
- 调用关系图用从上到下:上层调用下层,层次感强。
- 部署图用从上到下:接入层在上,数据层在下。
如果一张图里既有数据流又有调用关系,我一般以数据流为主方向,调用关系用垂直方向辅助。比如主链路从左到右,某个服务内部再往下展开子调用。
还有一个技巧:把最频繁交互的模块放在相邻位置。这样连线最短,图最干净。如果两个模块之间连线要绕一大圈,说明布局有问题,要么调整位置,要么考虑它们之间是不是真的需要直接交互。
3.3 第三步:先画主干,再补分支,最后加装饰
我画图的顺序固定是三步:
第一步,画主干。就是那条最核心的链路,比如“用户请求 → 网关 → 订单服务 → 库存服务 → 数据库”。这条链路用最粗的线、最醒目的颜色画出来。主干画完,整张图的骨架就有了。
第二步,补分支。主干之外的分支链路,比如“订单服务 → 消息队列 → 通知服务”,用细一点的线补上。异步链路用虚线,和同步链路区分开。
第三步,加装饰。图例、注释、边界框、颜色,这些最后加。装饰加早了,改起来麻烦,而且容易喧宾夺主。
这里有个我踩过的坑:不要一开始就追求完美对齐。我见过有人为了把两个框对齐,调了半小时。先大致摆好,最后统一用工具的对齐功能批量处理。思考的时间应该花在“这个模块该不该画”上,而不是“这个框往左移 2 像素”上。
3.4 第四步:用“反向验证法”检查图的完整性
图画完了,怎么知道它是不是完整、准确?我用一个方法叫反向验证:假设现在线上出了故障,我拿着这张图,能不能顺着图找到故障点?
具体做法是:从用户入口开始,沿着主干链路走一遍,每到一个节点问自己:
- 这个节点挂了,图上能看出来影响范围吗?
- 这个节点的上游和下游分别是谁,图上标清楚了吗?
- 这个节点有没有旁路或降级方案,图上体现了吗?
如果走一遍发现某个问题答不上来,说明图缺信息,回去补。我一般会走三条链路:正常链路、异常链路、降级链路。三条都能走通,这张图才算合格。
注意:反向验证的时候,最好找一个没参与画图的同事一起走。自己画的图自己有思维盲区,别人一眼就能看出“这个箭头到底指向谁”。
4. 架构流程图里那些符号和线型的门道
4.1 框的形状不是随便选的,每种形状有约定俗成的含义
虽然不同团队有自己的习惯,但行业内有一些通用的约定。我整理了一张表,是我自己在用的规范:
| 形状 | 含义 | 示例 |
|---|---|---|
| 矩形 | 服务/应用/进程 | 订单服务、网关 |
| 圆柱 | 数据库/存储 | MySQL、Redis |
| 圆角矩形 | 外部系统/第三方 | 支付平台、短信通道 |
| 平行四边形 | 消息队列/异步通道 | Kafka、RocketMQ |
| 菱形 | 判断/网关路由 | 鉴权判断、灰度路由 |
| 云形 | 外部网络/公网 | 用户端、CDN |
这套规范不是强制的,但一个团队内部必须统一。我见过一个团队,有人用圆柱表示服务,有人用圆柱表示数据库,评审的时候直接吵起来。后来他们定了一份“画图规范”,贴在 wiki 上,新人都照着来,效率高了很多。
4.2 线型承载的信息量比你想象的大
线型是架构图里信息密度最高的元素。我用线型的规则是:
- 实线粗箭头:核心同步调用,主链路
- 实线细箭头:非核心同步调用
- 虚线箭头:异步消息/事件
- 点线箭头:依赖关系(编译期、部署期)
- 双向箭头:双向通信,慎用,容易让人误解为循环依赖
这里重点说双向箭头。很多人在画“服务 A 和服务 B 互相调用”的时候,直接画一条双向箭头。但这样画有个问题:读者不知道是 A 调 B 多,还是 B 调 A 多,也不知道是不是有循环依赖。我的做法是画两条单向箭头,错开一点,并在旁边标注调用方向的主次。如果确实是循环依赖,那更要用两条线画出来,因为循环依赖本身就是需要重点关注的架构问题。
还有一个细节:箭头指向的是“被调用方”还是“数据接收方”,这个必须在图例里说清楚。我一般约定箭头指向数据接收方,也就是“数据往哪流,箭头往哪指”。这样最符合直觉。
4.3 颜色用得好是加分,用不好是灾难
颜色在架构图里的作用只有一个:区分类别。不是用来好看的。我用颜色的原则是:
- 最多用4 种颜色,超过 4 种人就记不住了
- 每种颜色对应一个明确的类别,比如蓝色=本团队服务,灰色=外部服务,绿色=数据存储,橙色=中间件
- 不要用红色表示“重要”,红色在架构图里通常表示“告警/故障/高风险”,容易引起误解
- 色盲友好:避免红绿搭配,可以用蓝橙搭配
我见过一张图用了十几种颜色,每个框颜色都不一样,问作者为什么,他说“这样好看”。结果评审的时候没人看得懂,全部注意力都被颜色分散了。颜色是信息,不是装饰,这个观念一定要建立起来。
4.4 文字标注的“三写三不写”
框里的文字怎么写,也有讲究。我的经验是“三写三不写”:
三写:
- 写服务名,不写机器名(写“订单服务”,不写“order-svc-01”)
- 写关键协议和端口(写“HTTP:8080”,不写“接口”)
- 写数据量级或频率(写“日均 100 万”,不写“大量”)
三不写:
- 不写实现细节(不写“用了 Spring Boot”,那是代码层面的事)
- 不写无意义的缩写(不写“SVC”,写“服务”)
- 不写过长的描述(框里超过 10 个字就考虑拆行或加注释)
我自己的习惯是:框里只放名词,动词放在线上。比如框里写“订单服务”,线上写“创建订单”。这样读起来就是“订单服务 → 创建订单 → 库存服务”,非常顺畅。
5. 工具选型:别在工具上纠结太久
5.1 我用过的几类工具和它们的适用场景
画架构图的工具大致分四类,我分别说说我的使用体验:
第一类:通用绘图工具(如 draw.io、ProcessOn)。优点是自由度高,想怎么画怎么画;缺点是容易画得乱七八糟,因为没有约束。适合画一次性、非标准的图。我一般用 draw.io 画评审用的草图,因为它免费、离线可用、导出格式多。
第二类:代码化绘图工具(如 PlantUML、Mermaid)。优点是可以版本控制,改起来方便,风格统一;缺点是需要学语法,调整布局不直观。我一般用 PlantUML 画需要长期维护的架构图,因为它可以跟着代码一起提交到 Git,改一行代码就能更新图。
第三类:专业架构工具(如 C4 模型相关的工具)。优点是强制分层,符合架构方法论;缺点是学习成本高,画简单图反而麻烦。适合大型系统的架构文档。
第四类:白板协作工具。优点是实时协作,适合远程评审;缺点是画复杂图时精度不够。我一般用在头脑风暴阶段。
我的建议是:日常评审用 draw.io,长期维护用 PlantUML,团队协作看情况。不要为了选工具纠结超过半天,工具只是手段,图的内容才是核心。
5.2 代码化绘图的一个实操示例
如果你决定用代码化工具,这里给一个 PlantUML 的最小示例,画一个简单的订单链路:
@startuml skinparam componentStyle rectangle actor "用户" as User component "API 网关" as Gateway component "订单服务" as Order component "库存服务" as Stock database "订单库" as OrderDB queue "消息队列" as MQ component "通知服务" as Notify User --> Gateway : HTTPS Gateway --> Order : HTTP:8080 Order --> Stock : gRPC:9090 Order --> OrderDB : SQL Order --> MQ : 异步消息 MQ --> Notify : 消费 @enduml这段代码生成的图,风格统一,改起来也方便。比如要把“库存服务”改成“库存中心”,只改一行就行。而且它可以提交到 Git,每次架构变更都有记录,比图片文件强太多。
提示:代码化绘图的一个坑是布局不可控。PlantUML 自动布局有时候会把线绕得很乱。我的经验是,节点超过 15 个就别用自动布局了,手动调或者换工具。
5.3 工具之外,更重要的是“图的版本管理”
这一点很多人忽略。架构图是会变的,今天画完,下个月可能就过时了。如果图没有版本管理,过时的图流传出去,比没有图还危险——因为会误导人。
我的做法是:架构图和代码放在同一个仓库,用 Markdown 或 PlantUML 源文件维护。每次架构变更,提交代码的同时更新图。评审的时候,看 Git 记录就知道这张图是什么时候、为什么改的。
如果团队用不了代码化工具,至少要做到:图上标注版本号和更新日期,并且指定一个负责人。我见过太多“三年前的架构图”还在被新人当参考,里面的服务早就下线了。
6. 评审现场:怎么把一张架构图讲明白
6.1 讲图的顺序:先讲边界,再讲主干,最后讲细节
很多人讲图是从左上角开始,一个框一个框地念。这样讲,听众很快就迷失了。我讲图的顺序固定是:
第一步,讲边界。“这张图里,蓝色是我们团队负责的,灰色是外部依赖,红色虚线是第三方。”一句话,听众就知道该重点关注哪块。
第二步,讲主干。“用户请求从左边进来,经过网关,到订单服务,再到库存服务,最后落库。”沿着主干走一遍,听众就有了全局观。
第三步,讲细节。“这里有个异步消息,订单创建后发到队列,通知服务消费后发短信。”细节放在最后讲,因为这时候听众已经有上下文了,容易理解。
第四步,讲异常和降级。“如果库存服务挂了,订单服务会走降级逻辑,先记录待扣减,后续补偿。”这一步最能体现架构的成熟度,也是评审时最容易被问到的。
6.2 预判评审时最容易被问的三个问题
根据我的经验,架构评审时被问得最多的三个问题是:
- “这个服务的边界为什么这么划?”—— 回答要点:职责单一、数据归属清晰、团队边界对齐。
- “这个链路挂了怎么办?”—— 回答要点:有没有降级、有没有重试、有没有熔断、影响范围多大。
- “为什么用这个中间件,不用那个?”—— 回答要点:性能、成本、团队熟悉度、运维复杂度,四个维度对比。
提前准备好这三个问题的答案,评审基本不会翻车。我一般会在图旁边附一页“设计决策记录”,把关键选择的理由写下来,评审时直接引用。
6.3 评审后的动作:把口头结论落到图上
评审会上讨论出来的结论,如果不落到图上,过两周就忘了。我的习惯是:评审结束后 24 小时内,更新架构图,并在图上用注释标出“评审结论”。比如“2024-06 评审:库存服务拆分为独立服务,Q3 完成”。
这样下次再看这张图,就知道当时的决策是什么、什么时候做的。架构图不只是描述现状,也是记录决策历史的载体。
7. 几个我踩过的坑和对应的解法
7.1 坑一:图太复杂,没人看
我最开始画的架构图,恨不得把每个类都画上去。结果发出去,没人看,因为太复杂了。后来我学乖了:一张图只讲一件事。要讲部署,就画部署图;要讲调用,就画调用图。不要混在一起。
如果确实需要在一张图里表达多个维度,用分层的方式:底层画部署,上层画服务,用不同颜色区分。但即使这样,也要控制总节点数在 20 个以内。
7.2 坑二:图更新不及时,变成“历史文物”
前面提过,架构图必须跟着代码走。我的解法是把图纳入 Definition of Done:一个需求做完,如果涉及架构变更,必须更新架构图,否则不算完成。这个规则一开始有人抵触,但坚持两个月后,大家就习惯了,因为受益的是所有人。
7.3 坑三:符号不统一,各画各的
团队里每个人画图习惯不一样,合并的时候就很痛苦。我的解法是制定一份团队画图规范,不用很长,一页纸就够:框的形状、线的类型、颜色的含义、图例的格式。新人入职第一周就学这个,后面省很多事。
7.4 坑四:只画了“正常情况”,没画“异常情况”
这是最隐蔽的坑。正常链路的图大家都画得好,但异常链路、降级链路、补偿链路往往被忽略。而这些恰恰是排障和评审时最需要的。我的解法是:每张核心架构图,必须配一张异常流程图,至少标出三个关键故障点的处理方式。
8. 关于架构流程图,我最后想分享的几点体会
画了这么多年架构图,我最大的体会是:图是思考的产物,不是思考的替代品。如果你对系统理解不深,画出来的图一定是乱的;反过来,画图的过程本身就是在逼你把系统想清楚。我经常在画图的过程中发现“这两个服务之间的数据流我居然说不清楚”,然后回去看代码、问同事,把这块补上。
另一个体会是:架构图的价值在于沟通,不在于好看。我见过很多漂亮的图,配色讲究、对齐完美,但看完不知道系统怎么工作。也见过手绘的草图,歪歪扭扭,但一眼就能看懂数据怎么流。后者才是好图。
最后一个实用建议:每次画完图,找一个没参与的人看五分钟,然后让他复述一遍系统怎么工作。如果他复述得八九不离十,这张图就成功了;如果他一脸茫然,别怪他,回去改图。这个“五分钟复述测试”是我用过最有效的图质量检验方法,没有之一。
架构流程图这件事,说到底就是把脑子里的系统模型,用别人能看懂的方式画出来。工具、符号、颜色都是手段,核心是你对系统的理解,以及你站在读者角度思考的能力。这两点做到了,图自然就清楚了。