3. 机器学习数据平台集成架构
机器学习项目失败的原因,往往不在算法本身,而在数据链路。一个可复用的 ML 数据平台,需要把"数据从哪来、怎么进来、放在哪、怎么算、怎么用"这五个问题拆成清晰的层次,让每一层只解决一类问题,层与层之间通过稳定的接口衔接。本节讨论的正是这种分层设计:数据源层、采集层、存储层、计算层、服务层,以及 Elastic 在这条链路中究竟站在什么位置。
五层架构的职责边界
分层的第一价值是"变更隔离"。当上游数据源从 MySQL 换成 Kafka,理想情况下只应改动采集层;当特征计算从批处理改为流式,只应改动计算层。如果各层职责混杂,任何一处变动都会引发全链路返工。
- 数据源层:业务库(MySQL、PostgreSQL)、日志文件、消息队列(Kafka、Pulsar)、对象存储(S3、OSS)、第三方 API、埋点 SDK。这一层的关键属性是"数据产生方式"——是事务写入、追加日志,还是定时拉取。
- 采集层:负责把源数据搬运到平台内,并完成格式统一、时间戳对齐、脏数据过滤。常见组件包括 Logstash、Filebeat、Fluent Bit、Kafka Connect、Flink CDC、DataX。采集层要回答的核心问题是"全量还是增量、实时还是批量、是否允许丢数据"。
- 存储层:按用途分为原始区(Raw/ODS)、明细区(DWD)、汇总区(DWS)和特征区(Feature Store)。技术选型上,对象存储承担低成本冷数据,Elasticsearch 承担检索与聚合,ClickHouse/Doris 承担 OLAP 分析,Redis 承担在线特征低延迟读取。
- 计算层:批处理(Spark、Hive)、流处理(Flink、Spark Streaming)、特征工程、模型训练与调优。计算层消费存储层的数据,产出模型文件和特征表,回写到存储层或直接推送到服务层。
- 服务层:模型推理 API、特征在线查询、A/B 实验分流、监控告警。服务层直接面对业务调用方,对延迟、可用性、版本管理要求最高。
数据在层间的流动形态
理解分层不能只看静态的方框,更要看数据在层间"变成什么"。以一条电商用户行为日志为例:在数据源层它是带业务字段的 JSON 事件;进入采集层后被补齐 ingest_time、清洗掉非法字段,转为统一 schema;落到存储层时,原始 JSON 存入对象存储做归档,同时写入 Elasticsearch 供检索;计算层从 Elasticsearch 或数仓读取,按用户维度聚合出"近 7 天点击品类分布"等特征;服务层则把特征以毫秒级响应返回给推荐模型。同一份数据在五层中形态不同、时效不同、精度要求也不同,这正是分层存在的意义。
Elastic 在分层中的真实定位
很多团队把 Elasticsearch 简单归为"存储层的一个数据库",这低估了它的作用,也容易导致架构误用。从分层视角看,Elastic 实际上横跨了三个位置:
第一,采集层的接入端。Filebeat、Logstash、Elastic Agent 本身就是采集层的主流组件,它们把日志、指标、事件统一送入 Elasticsearch,同时完成字段解析、时间戳处理和基础清洗。在这个意义上,Elastic 生态提供了采集层的一部分能力。
第二,存储层的检索与聚合引擎。Elasticsearch 擅长的是"带条件的快速检索 + 多维聚合",例如按用户 ID 查最近行为、按时间窗口统计点击量、按品类做嵌套聚合。它不适合承担大规模明细数据的全量扫描和复杂 JOIN,那类工作应交给 ClickHouse 或 Spark。把 Elasticsearch 当作唯一存储,往往在数据量增长后遇到分片膨胀和聚合延迟问题。
第三,服务层的特征读取后端。在线推理需要毫秒级读取用户画像和近期行为特征,Elasticsearch 的 _mget 和 _search 可以承担这一角色,尤其是当特征本身带有文本检索需求时(如"用户最近搜索过的商品标题")。但纯数值型、超低延迟的特征,Redis 仍是更优选择。
一个可落地的分层参数示例
下面给出一组教学示例参数,用于说明各层在真实项目中如何设定关键指标。这些数值属于合理假设,实际项目需根据数据量和 SLA 调整。
| 层次 | 关键组件 | 示例参数 | 判断依据 |
|---|---|---|---|
| 数据源层 | Kafka Topic | 3 分区,副本数 2 | 峰值 5000 条/秒,单分区约 1700 条/秒 |
| 采集层 | Logstash Pipeline | batch.size=125,workers=4 | 消费延迟 < 2 秒 |
| 存储层 | Elasticsearch Index | 5 主分片,1 副本,rollover 50GB | 单分片 10–30GB 为健康区间 |
| 计算层 | Spark 特征任务 | executor 4 个,每核 4GB | 7 天窗口特征计算 < 15 分钟 |
| 服务层 | 推理 API | P99 < 80ms | 特征查询 + 模型推理总耗时 |
分层设计中最容易犯的三个错误
错误一:采集层做重计算。有人在 Logstash 里写复杂 Ruby 脚本做特征聚合,导致采集吞吐骤降。采集层只应做轻量清洗和格式转换,重计算交给计算层。
错误二:存储层职责重叠。同一份数据既写 Elasticsearch 又写 ClickHouse,却没有明确"谁服务检索、谁服务分析",结果两边数据不一致,排查成本极高。正确做法是按查询模式分工:检索走 Elasticsearch,OLAP 走 ClickHouse,并明确同步链路和延迟容忍度。
错误三:服务层直接查原始索引。推理 API 直接对原始日志索引做聚合查询,随着数据增长延迟飙升。应通过计算层预生成特征索引或特征表,服务层只读特征结果,不碰原始数据。
分层不是目的,而是让每一层的变化不波及全局。Elastic 在这套架构中的价值,不在于替代数仓或计算引擎,而在于把"检索、聚合、在线特征读取"这三件事做到足够快、足够灵活。认清它的边界,比盲目扩大它的职责更重要。