Feature Store 架构解析:在线存储、离线存储、特征注册表、特征服务层
Feature Store 的核心架构由四个紧密协作的组件构成:离线存储、在线存储、特征注册表和特征服务层。理解这四者的职责与交互方式,是进行巡检和故障定位的基础。
架构总览:四层职责与数据流
下图展示了 Feature Store 的典型分层架构,以及特征数据从生产到消费的完整生命周期。
1. 离线存储 (Offline Store)
离线存储负责保存全量历史特征数据,主要用于模型训练、批量评估和特征回溯。它是 Feature Store 的“数据湖”,通常基于分布式存储或数据仓库构建。
| 属性 | 说明 |
|---|---|
| 存储介质 | HDFS / S3 / GCS / 云数据湖 |
| 数据格式 | Parquet / Avro / ORC (列式存储优先) |
| 写入模式 | 批量 ETL (Spark / Flink Batch) 或流式写入的 Checkpoint |
| 查询接口 | Spark SQL / Presto / Hive / BigQuery |
| 典型巡检指标 | 数据分区完整性、数据延迟 (Data Freshness)、文件大小分布 |
巡检提示: 离线存储的“数据空洞”是常见问题。检查最近 N 个分区的数据行数是否在合理阈值内,避免因上游任务失败导致训练数据集缺失。
2. 在线存储 (Online Store)
在线存储为实时推理提供毫秒级特征访问。它只保存最新的特征快照,通常使用键值数据库或内存缓存,以支持高并发、低延迟的读取。
| 属性 | 说明 |
|---|---|
| 存储介质 | Redis / DynamoDB / Cassandra / Aerospike |
| 数据模型 | Key-Value (实体ID → 特征向量) |
| 写入模式 | 流式写入 (Kafka → Flink → Online Store) 或离线批量同步 |
| 查询延迟 | P99 < 10ms (典型目标) |
| 典型巡检指标 | 缓存命中率、连接池使用率、读写延迟 P99、数据过期策略 |
常见故障: 在线存储与离线存储的数据不一致。例如,离线表已更新特征,但在线缓存未刷新,导致训练与推理特征分布偏移。巡检时应对比关键特征的离线最新值与在线最新值。
3. 特征注册表 (Feature Registry)
特征注册表是 Feature Store 的元数据中心,存储所有特征的“定义”而非“值”。它记录了特征名称、类型、来源、版本、血缘关系以及 Serving 配置。
- 核心实体: Feature Group (特征组)、Feature View (特征视图)、Feature Version (特征版本)。
- 关键元数据: 特征名称、数据类型 (int/float/string)、维度、描述、创建时间、上游数据源、下游模型列表。
- 存储方案: 关系型数据库 (PostgreSQL/MySQL) 或专门的元数据服务 (如 Hive Metastore)。
- 巡检重点: 元数据完整性 (是否存在孤儿特征)、版本冲突、血缘链路断裂。
巡检命令示例: 检查注册表中是否存在未被任何模型引用的“孤儿特征”,这些特征可能占用存储资源且无人维护。
# 伪代码:查询未被引用的特征
SELECT f.feature_name
FROM feature_registry f
LEFT JOIN model_feature_mapping m ON f.feature_id = m.feature_id
WHERE m.model_id IS NULL;
4. 特征服务层 (Serving Layer)
特征服务层是 Feature Store 的统一入口,对外提供特征检索 API。它屏蔽了底层离线/在线存储的差异,根据请求上下文自动路由到正确的存储后端。
| 能力 | 说明 |
|---|---|
| 统一 API | 提供 get_online_features() 和 get_historical_features() 接口 |
| 路由逻辑 | 根据特征注册表中的 Serving Store 配置,决定从 Redis 还是 Hive 读取 |
| 实时计算 | 支持在服务层执行简单的特征变换 (如聚合、时间窗口计算) |
| 协议 | gRPC (高性能) / RESTful (通用) / Python SDK |
| 典型巡检指标 | API 响应延迟、错误率 (4xx/5xx)、吞吐量 (QPS)、服务层与存储层连接健康度 |
组件交互流程:一次完整的特征服务请求
下图展示了一个在线推理请求在 Feature Store 内部的完整流转路径。
巡检核心指标速查表
| 组件 | 关键指标 | 健康阈值参考 |
|---|---|---|
| 离线存储 | 数据新鲜度 (Data Freshness) | 最近分区写入时间 < 1 小时 |
| 离线存储 | 分区完整性 | 连续 N 个分区无缺失 |
| 在线存储 | P99 读取延迟 | < 10ms |
| 在线存储 | 缓存命中率 | > 99% |
| 特征注册表 | 元数据响应时间 | < 50ms |
| 特征注册表 | 孤儿特征比例 | < 5% |
| 特征服务层 | API 错误率 (5xx) | < 0.1% |
| 特征服务层 | 端到端 P99 延迟 | < 30ms |
巡检脚本片段: 检查在线存储与离线存储的特征值一致性。
# 伪代码:对比离线与在线特征
offline_value = spark.sql("SELECT feature_a FROM offline_store WHERE entity_id='123'")
online_value = redis_client.get("feature_a:123")
if offline_value != online_value:
alert("数据不一致: entity_id=123, feature_a")