3.6 draw.io 架构图
学习目标
完成本节后,你将能够:
- 打开本书配套的 draw.io XML 架构图。
- 按中文图例识别 Langfuse 的入口层、契约层、执行层和状态层。
- 用这张图复述 ingestion、查询和 worker 队列的组合方式。
3.6.1 图在哪里
draw.io XML 文件在:
- 站点可访问版本:architecture/langfuse-current-architecture.drawio
- 源文件位置:
architecture/langfuse-current-architecture.drawio
这两个文件内容保持一致。在线阅读时可以直接下载站点可访问版本;在仓库里维护时改源文件。这个文件是标准 draw.io XML,可以用 diagrams.net 打开。打开后建议先把缩放调到“适合页面”,再按图中的五个泳道阅读。
3.6.2 这张图不是目录树
图里故意按运行职责分层:
| 泳道 | 读法 | 关键问题 |
|---|---|---|
| 外部入口 | 谁在系统外部调用 Langfuse | Browser、SDK、OTel、API client 分别走哪条入口。 |
web/ | 同步产品界面和 API 入口 | 哪些逻辑必须在 HTTP 请求内完成。 |
packages/shared | 跨运行时契约中心 | 哪些 schema、queue payload、filter、query 语义必须共享。 |
worker/ | 异步执行层 | 哪些工作离开请求链路,如何被 BullMQ 调度。 |
| 数据与基础设施 | 状态落点 | Postgres、ClickHouse、Redis、S3 各自保存什么。 |
如果你把它读成“上面目录调用下面目录”,就会误解系统。真实情况是:web 和 worker 不直接互相 import,它们通过 packages/shared 里的契约、Redis/BullMQ job、S3 raw payload 和数据库状态连接。
3.6.3 三条主链路怎么在图上追
UI 查询链路
从“浏览器 UI”开始,追到 Next.js App + Pages UI,再到 tRPC 根路由、查询契约、ClickHouse v4 events 或 Postgres。
这条线要看:
protectedProjectProcedure如何建立 session 和 project scope;FilterState如何从 UI/search bar 进入后端;EventsQueryBuilder如何决定读events_core还是events_full。
Public API 链路
从“SDK / 公共 API 客户端”开始,追到“公共 REST API”,再进入 Zod schema、服务和状态设施。
这条线要看:
- API key 鉴权和 rate limit;
- request/response schema;
- Fern contract 和 generated client 是否需要同步。
Ingestion 写入链路
从“SDK / OTel 上报”开始,追到 /api/public/ingestion,再到 processEventBatch、队列契约、S3、Redis、WorkerManager、摄取处理器、ClickhouseWriter、ClickHouse。
这条线是本 repo 最适合初学者学习 infra 的主线,因为它同时经过:
- 外部 payload runtime schema;
- raw payload 存储;
- queue payload contract;
- worker retry 和 secondary queue;
- batch writer;
- OLAP 写入和查询投影。
3.6.4 图例对应的设计原则
| 图例 | 设计含义 |
|---|---|
| 实线 | 主运行路径,应该能从入口追到状态落点。 |
| 虚线 | 条件路径、legacy 路径、双写路径,改动前要检查开关和兼容。 |
| 黄色契约层 | web、worker、ee 共同依赖的稳定协议,不是普通 helper。 |
| 绿色 worker 层 | 可重试、可限流、可批量的后台执行,不应该承担同步响应。 |
| 红色状态层 | 系统事实和调度状态,读图时要问“为什么是这个存储”。 |
3.6.5 读图时要带走的结论
打开 XML 后,不要只看连线数量,要把下面几条结论直接记到运行模型里:
| 结论 | 原因 |
|---|---|
| SDK 上报 observation 后,Redis job 不直接放完整 body。 | 大 payload 会压 Redis 内存,也不利于重放;Langfuse 把 raw event 放到 S3/blob,job 只传 pointer 和 scope。 |
bucketPrefix 属于 queue payload contract。 | producer 写 S3 时最知道真实路径;worker 重新拼路径会受 env、部署版本和 legacy fallback 影响。 |
UI event list 默认更适合读 events_core。 | 列表页主要需要轻字段、筛选、排序和分页;完整 input/output/metadata 应按需从 events_full 读取。 |
| 新增后台任务要同时考虑 contract、producer、consumer、registration 和 failure semantics。 | 队列不是函数调用。没有 shared payload,producer 和 worker 会在滚动部署或旧 job 上漂移。 |
只改 worker/src/queues/** 不等于完成 queue 设计。 | queues.ts 才是跨进程协议源头;缺它就没有稳定的 queue name、job name、payload schema 和类型映射。 |
这些结论在第 4 篇运行链路和第 5 篇契约章节里都会展开,不需要额外做题来补充。