服务拓扑怎么画:一张图讲清三层边界
一张图为什么会失真
大部分架构图的问题不是画得丑,而是混层:把公网入口、进程、数据库、定时任务全塞进同一张平面图,读者分不清哪条线是网络跳转、哪条是函数调用。
解决办法是把拓扑拆成三层,每层只回答一个问题:
第一层 · 流量层
请求从哪进来、经过哪些网络跳转。只画公网可达的边界。
第二层 · 进程层
哪几个进程在跑、谁调谁。只画同一台机器或同一编排单元内的进程。
第三层 · 数据层
数据落在哪、谁写谁读。只画存储与读写方向。
判断标准
如果一张图里既有 https:// 又有 SELECT,那它一定混层了。拆开画。
三层合起来长这样
下面这张是典型的单机双服务部署,把三层叠在一张图里,但用节点形状区分职责。
服务拓扑(三层叠合) Mermaid
形状约定
圆角矩形 = 网络实体,方括号 = 进程,圆柱 = 存储,虚线 = 非同步/旁路。约定统一了,图就有信息量。
落地配置
三层边界最终都要落到配置文件上,改完再用一条命令验证:
# nginx:手工管理证书与上游
server {
listen 443 ssl http2;
server_name kb.example.com;
ssl_certificate /etc/ssl/kb.crt;
ssl_certificate_key /etc/ssl/kb.key;
location /api/ { proxy_pass http://127.0.0.1:8000; }
location / { root /srv/kb/current; }
}# docker compose:把三层写成三个 service
services:
edge:
image: caddy:2-alpine
ports: ["443:443"]
volumes: ["./Caddyfile:/etc/caddy/Caddyfile"]
app:
build: .
expose: ["8000"]
job:
build: ./job
depends_on: [app]# 验证三层是否真的通了:静态、API、证书各打一发
curl -sI https://kb.example.com/ | head -1
curl -s https://kb.example.com/api/health
echo | openssl s_client -connect kb.example.com:443 2>/dev/null \
| openssl x509 -noout -dates Caddy 的等价写法
如果不想手工管证书,同样的需求换成 Caddy 只要三行:域名块 + handle /api/* 反代 + handle 静态。
证书签发和续期 Caddy 自己包了,代价是少一层精细控制。
常见坑
Caddy 的 handle 是互斥的,handle_path 会剥掉前缀。用 handle /api/* 转发时上游收到的是带前缀的路径,FastAPI 的路由要相应加上 /api 前缀,否则全 404。
一张手绘草图胜过十段描述
和同事对齐拓扑时,先画后写。下面这种草图式布局最快:
收尾
架构图的价值不在于画得全,而在于让读者一眼看出「哪条线断了会炸」。
画完三层之后,回头在每个节点旁标一个数字:这台服务挂掉,影响多少用户。标注完,优先级自然就出来了。