3. 数据目录架构设计:分层架构、核心模块与存储选型
数据目录这东西,说白了就是一个「元数据的搜索引擎」。但真要把它搭好,光靠一个数据库加个搜索框可不行。我在几个大厂都做过数据目录的从零搭建,踩过的坑能写满一页A4纸。今天咱们就聊聊架构层面的几个关键决策点。
3.1 分层架构:为什么必须拆成三层?
我见过不少团队,一开始图省事,把采集、存储、展示全塞在一个服务里。结果呢?数据源一多,采集任务把查询接口拖垮了;或者查询压力一大,采集任务直接超时。嗯,这里要注意——分层不是炫技,是解耦。
我个人习惯把数据目录拆成三层:
- 采集层(Ingestion Layer):负责从各种数据源拉取元数据。比如Hive的表结构、Kafka的Topic Schema、Airflow的DAG定义。
- 存储层(Storage Layer):把采集到的元数据持久化,同时提供查询能力。
- 服务层(Service Layer):对外提供API和UI,处理搜索、血缘、权限等业务逻辑。
你想想看,这三层各干各的,互不干扰。采集层挂了,不影响用户查数据;存储层做扩容,采集层照常跑。我在一个项目中就遇到过,采集层用Celery做异步任务,存储层用图数据库,服务层用Go写REST API。各层之间通过消息队列解耦,爽得很。
核心原则:采集层只管「拿数据」,存储层只管「存和查」,服务层只管「加工和展示」。谁也别越界。
3.2 核心模块设计:四个必须有的组件
分层定好了,接下来就是每个层里要放什么模块。我总结下来,有四个模块是绕不开的:
3.2.1 元数据采集器(Scanner)
这东西负责连接数据源,拉取元数据。每个数据源类型都要写一个适配器。比如:
- Hive Scanner:通过JDBC读取INFORMATION_SCHEMA
- Kafka Scanner:通过AdminClient读取Topic和Schema
- Airflow Scanner:通过REST API读取DAG和Task定义
我曾经踩过一个坑——采集器全量扫描时,直接把Hive Metastore打挂了。后来改成增量采集+限流,才稳住。所以采集器一定要支持增量模式,别每次都全量扫。
3.2.2 元数据解析器(Parser)
采集回来的原始数据是「脏」的。比如Hive的DDL里可能混着注释、分区信息、存储格式。解析器要把它拆成结构化字段:表名、列名、类型、注释、分区键……
这里有个小技巧:解析器最好做成插件化。新数据源来了,写个Parser插件就行,不用改主流程。
3.2.3 血缘分析引擎(Lineage Engine)
血缘是数据目录的灵魂。它能告诉你「这张报表的数据是从哪张表来的,中间经过了哪些ETL」。实现方式有两种:
- 解析SQL:从INSERT、SELECT语句里提取输入表和输出表
- 解析执行计划:从Spark/Flink的执行计划里提取更细粒度的血缘
我个人更推荐第二种,因为SQL解析容易漏掉子查询和UDF里的血缘。但执行计划解析更复杂,需要对接每个计算引擎。嗯,这里要权衡。
3.2.4 搜索与索引模块(Search & Index)
用户找表,靠的是搜索。别指望用户记得表名,他们通常只记得「订单」「用户」「最近三天」这种关键词。所以搜索模块必须支持全文检索和模糊匹配。
我一般用Elasticsearch做索引层,把表名、列名、注释、标签全倒进去。查询时还能做分词、同义词、权重排序。效果比直接查数据库好太多。
提示:搜索模块别忘了做「热词推荐」。用户搜「订单」时,把「订单表」「订单明细」「订单日志」排在前面。这个小功能能大幅提升用户体验。
3.3 元数据存储选型:关系型 vs 图数据库
这是架构设计里争议最大的一个点。我直接说结论:没有银弹,看场景。
先看一张对比表:
| 维度 | 关系型(PostgreSQL/MySQL) | 图数据库(Neo4j/JanusGraph) |
|---|---|---|
| 数据模型 | 表、行、列 | 节点、边、属性 |
| 血缘查询 | 需要多层JOIN,深度>3层性能急剧下降 | 天然支持多跳遍历,毫秒级返回 |
| 元数据变更 | ALTER TABLE加列很方便 | 节点属性变更灵活,但Schema变更需迁移 |
| 事务支持 | 强ACID,成熟稳定 | 弱事务,部分场景需补偿 |
| 运维成本 | 低,DBA都会 | 高,需要专门团队 |
| 典型场景 | 表/列元数据管理、标签管理 | 血缘追踪、影响分析、数据地图 |
我个人的建议是:用关系型做主存储,用图数据库做血缘查询的加速层。说白了就是双写——元数据主体存在PostgreSQL里,血缘关系同步到Neo4j里。查询血缘时走图数据库,查表结构时走关系型。
为什么这么搞?我在一个项目里试过纯图数据库方案。血缘查询确实快,但做「给某张表加个标签」这种简单操作,图数据库的API反而不如SQL顺手。而且图数据库的备份恢复、扩容迁移,都比关系型麻烦得多。
警告:别为了「炫技」强行上图数据库。如果你的数据目录只有几百张表,血缘深度不超过3层,PostgreSQL完全够用。图数据库的优势在「千表级别、血缘深度>5层」时才真正体现出来。
3.4 架构总览:一张图说清楚
下面这张图是我在多个项目中沉淀下来的数据目录架构。你可以把它当成一个「参考模板」:
3.5 选型决策树:帮你快速做决定
如果你还在纠结用关系型还是图数据库,试试这个决策树:
- 数据表数量 < 500 → 直接用PostgreSQL,别折腾
- 数据表数量 500~2000 → PostgreSQL + 血缘关系用图数据库(只存边)
- 数据表数量 > 2000 → 双写:PostgreSQL存元数据,Neo4j存血缘,Elasticsearch存搜索
- 需要实时血缘分析(秒级) → 必须上图数据库,关系型扛不住多跳查询
- 团队没有图数据库运维经验 → 先用PostgreSQL顶着,等招到人再迁移
我记得有个团队,上来就选了Neo4j做唯一存储。结果半年后,元数据量涨到10万节点,Neo4j的备份恢复要4个小时,每次升级都提心吊胆。后来还是加了PostgreSQL做冷备。所以别把鸡蛋放在一个篮子里。
我的经验:如果预算允许,可以试试「关系型+图数据库+搜索引擎」三件套。关系型保底,图数据库加速血缘,搜索引擎提升用户体验。虽然运维成本高了点,但数据目录这东西,一旦用起来,用户对查询速度的容忍度极低。
3.6 小结
数据目录的架构设计,说白了就是三个问题:怎么采、怎么存、怎么查。分层架构解决「怎么采」的解耦问题;核心模块解决「怎么查」的业务问题;存储选型解决「怎么存」的性能问题。别想着一步到位,先跑起来,再根据实际瓶颈做优化。