什么是 C4 模型图?
该C4 模型图是一种分层的四层架构框架,旨在以不同粒度的详细程度记录软件架构。由西蒙·布朗创建的 C4 通过将系统图结构化为四个明确的抽象视角,避免了模糊的方框和线条:上下文(系统级范围),容器(应用程序和数据存储),组件(内部模块),以及代码(类级别实现)。
为了在文本中有效实现该模型,工程师使用官方的C4-PlantUML标准库扩展。该库用专用宏替换了原始的 UML 形状,可自动注入用户、系统和数据库的特定颜色、形状和元数据字段。使用VPasCode,您可以在代码中清晰地定义这些嵌套环境。布局引擎可动态路由连接向量并缩放文本字段,而不会破坏您的布局几何结构。
核心语法指南:元素与构造
使用 PlantUML 构建有效的 C4 模型,依赖于导入正确的库文件、选择结构化宏、建立边界以及使用专用的关系链接。
1. 导入 C4 标准库文件
该C4-PlantUML扩展被拆分为多个独立文件,直接对应抽象模型的不同层级。为避免性能下降或编译错误,您应仅导入图表所针对的特定文件层:
@startuml
' 包含所需的特定 C4 层文件
!include <C4/C4_Context>
' 使用 C4_Container 或 C4_Component 以构建更深入的架构图
2. 声明核心参与者和系统(上下文层级)
在高层的系统上下文层级中,您需要建模内部组件、外部依赖关系以及人类终端用户。标准库提供了特定的宏,接受 ID、视觉标签和可选的描述性标签:
Person(id, "标签", "描述")— 表示一个人类用户档案或系统参与者。System(id, "标签", "描述")— 表示一个主要的内部软件应用程序或服务生态系统。System_Ext(id, "标签", "描述")— 表示一个外部系统或第三方API依赖(以明确的灰色调显示)。
@startuml C4_Elements
!include <C4/C4_Context>
Person(customer, "银行客户", "拥有个人银行账户的客户")
System(banking_sys, "核心银行系统", "处理金融交易")
System_Ext(mail_sys, "电子邮件服务", "内部SMTP通知网关") 
3. 爆炸边界(容器与组件层级)
深入到容器层时,您将建模Web应用、微服务和数据库。您可以使用以下宏包装器,将这些内部元素隔离在明确的逻辑边界框内:System_Boundary()宏包装器:
!include <C4/C4_Container>
System_Boundary(c1, "电子商务系统生态系统") {
Container(web_app, "单页应用", "React & TypeScript", "通过网页视图提供用户功能")
ContainerDb(database, "关系型数据库", "PostgreSQL", "存储用户资料和账本历史记录")
} 
4. 映射技术关系
与其依赖基本的虚线,C4采用明确的通信宏格式:Rel(From_ID, To_ID, "标签", "技术")。这使得您的架构图高度可读,因为强制要求每个连接都明确其目的和底层传输协议(如HTTPS、gRPC或AMQP):
!include <C4/C4_Container>
Person(customer, "银行客户", "拥有个人银行账户的客户")
System(banking_sys, "核心银行系统", "处理金融交易")
System_Ext(mail_sys, "电子邮件服务", "内部SMTP通知网关")
System_Boundary(c1, "电子商务系统生态系统") {
Container(web_app, "单页应用", "React & TypeScript", "通过网页视图提供用户功能")
ContainerDb(database, "关系型数据库", "PostgreSQL", "存储用户资料和账本历史记录")
}
Rel(customer, web_app, "通过", "HTTPS")
Rel(web_app, database, "通过", "SQL/TCP") 
可读C4架构的最佳实践
- 切勿混合抽象层级: 保持您的图表聚焦于单一层次。不要将细粒度的内部软件组件混入高层级的系统上下文图中。如果系统过于复杂,应将其拆分为一个独立的、专门的容器层级图。
- 明确定义技术: 始终使用您宏的第四个参数来明确说明所使用的确切技术或协议(例如:
Rel()宏来说明所使用的精确技术或协议(例如:"JSON/HTTPS"或"JDBC").这能让您的团队一目了然地掌握关键的实现背景。 - 利用方向性布局覆盖: 如果您的组件开始出现堆叠不自然的情况,可使用方向性关系宏(如
Rel_D()表示向下,Rel_R()表示向右,或Rel_L()表示向左)手动优化您的架构流程。
真实世界的 PlantUML C4 示例
示例 1:高层系统上下文布局(层级 1)
此功能蓝图建模了一个标准的层级 1 系统上下文图,详细说明了客户如何与互联网银行应用程序及其外部依赖项进行交互。
@startuml
!include <C4/C4_Context>
title 互联网银行系统上下文图
Person(customer, "个人银行客户", "拥有个人账户的银行客户。")
System(banking_system, "互联网银行系统", "允许客户查看财务信息并进行转账。")
System_Ext(mail_system, "电子邮件子系统", "企业内部的 SendGrid 企业邮件服务器集群。")
Rel(customer, banking_system, "通过在线仪表板使用")
Rel_R(banking_system, mail_system, "使用", "SMTP")发送警报和验证代码
@enduml 
语法解析: 该图仅关注高层范围。System_Ext 宏会自动为电子邮件服务应用灰色配色方案,从视觉上将核心系统与外部依赖项区分开。Rel_R 宏强制布局引擎将邮件节点直接放置在银行系统模块的右侧。
示例 2:深入剖析微服务容器拓扑(层级 2)
此高级企业蓝图将系统分解为其构成的容器应用程序和独立的数据存储,展示网络流量如何通过 API 网关流向后端微服务。
@startuml
!include <C4/C4_Container>
title 支付门户网关容器图
Person(merchant, "网络商户合作伙伴", "将平台结账端点集成到其网站中。")
System_Boundary(portal_scope, "支付网关生态系统") {
Container(api_gateway, "API 路由代理", "Nginx", "拦截入站调用,处理速率限制并均衡节点。")
Container(auth_service, "身份微服务", "Go & OAuth2", "验证开发者 API 令牌和权限范围。")
Container(txn_service, "交易账本", "Java Spring Boot", "处理支付并管理账本账户。")
ContainerDb(ledger_db, "账本数据存储", "CockroachDB", "实现分布式 ACID 兼容的表结构。")
}
' 路由流量顺畅地穿过内部容器目标
Rel(merchant, api_gateway, "通过", "HTTPS/JSON")提交支付数据
Rel_D(api_gateway, auth_service, "通过", "gRPC")验证传入令牌
Rel_D(api_gateway, txn_service, "将结账操作转发至", "gRPC")
Rel_R(txn_service, ledger_db, "通过", "SQL/TLS")持久化账本条目
@enduml 
语法分解: 通过使用 System_Boundary 宏包装器,内部组件被清晰地分组在明确的边界框内。专用的 ContainerDb 宏以明确的数据库圆柱图标渲染数据存储,使计算运行时与持久存储层之间的划分一目了然。