Feature Store · 特征存储¶
一句话定位
ML 特征的一等公民。解决三大痛点:训推一致、Point-in-Time 正确、特征复用。它不是 Redis 的别名——是一个定义 + 离线存储 + 在线存储 + 注册目录 + 监控一体化平台。推荐 / 风控 / 个性化场景的 MLOps 必备。
SSOT · 主定义页
本页是 PIT Join · Train-Serve Skew 等概念的手册内主定义页。其他场景 / 概念页在引用时会链回这里。
TL;DR
- 核心能力:统一定义 + PIT Join + 双存储(离线 Parquet/Iceberg · 在线 Redis/KV)
- 解决的三大痛:训推 skew / PIT 泄露 / 特征复用
- 组件选型:Feast(开源首选)· Tecton(商业 SaaS)· Hopsworks(MLOps 一体)· Databricks FS / Vertex / SageMaker(各云厂商)· 自建(小团队)
- "自建 Feast 级"几乎都低估:PIT Join 是事故温床
- 典型 SLO:离线批 PIT Join 分钟-小时级;在线 KV < 10ms
- 对标对比详见 Feature Store 横比
1. 业务痛点 · 没有 Feature Store 的典型事故¶
痛点 1 · Train-Serve Skew(训推漂移)¶
- 场景:离线训练用 Spark SQL 计算
user_last_7d_gmv - 在线推理时,工程师用 Java 重写一遍这段逻辑
- 两套代码必然漂移(timezone、null 处理、范围边界)
- 典型事故:离线 AUC 0.92 → 线上 AUC 0.74 → 业务问 "为什么模型不行"
没人发现是特征不一致,模型被误认为"没调好"。
痛点 2 · Point-in-Time 泄露¶
经典错误:训练 2024-06 订单时,拼了 2024-06 当前的 user_total_gmv。但这个值包含了 6 月之后的订单——未来信息泄露到训练。
订单日期 = 2024-06-15
user_total_gmv @ 2024-06-15 = $5000 ← 正确的特征值
user_total_gmv @ 2024-12-01 = $15000 ← 错误!泄露了未来
症状:离线 AUC 0.95,线上崩盘。
痛点 3 · 特征复用困难¶
- 推荐组算了一套
user_embedding - 风控组不知道 → 自己再算一套
- 广告组再算一套
- 都算了却没人对账,三套数值不一致
- 浪费 × 混乱 × 无法审计
Feature Store 的三个核心能力¶
| 能力 | 解决的痛 |
|---|---|
| 统一定义(一处定义、离线在线同算) | Train-Serve skew |
| Point-in-Time Join | PIT 泄露 |
| Feature Registry(目录 + 血缘) | 复用困难 |
2. 原理深度 · 核心概念¶
关键抽象¶
| 概念 | 含义 |
|---|---|
| Entity | 特征关联的实体(user, item, order) |
| Feature | 一个原子属性(avg_7d_gmv, is_vip) |
| Feature View | 一组相关 Feature 的集合 |
| Feature Service | 为一个模型聚合多个 Feature View |
| Online Store | 低延迟 KV(Redis / DynamoDB) |
| Offline Store | 历史全量(Iceberg / Parquet / BigQuery) |
| Registry | 元数据目录、血缘、版本 |
| Materialization | 把离线特征物化到在线 |
架构一览¶
flowchart LR
subgraph "离线(训练)"
src[(业务 DB / Kafka / 湖)]
src --> etl[Spark / dbt / Flink]
etl --> offline[(Offline Store<br/>Iceberg / Parquet)]
offline --> pitj[PIT Join]
pitj --> train[训练集]
train --> model[模型训练]
end
subgraph "在线(推理)"
offline -->|Materialize| online[(Online Store<br/>Redis / DynamoDB)]
stream[Flink 实时流] --> online
online --> fetch[Feature Fetch]
fetch --> infer[模型推理]
end
subgraph "Registry + 监控"
reg[Feature Registry]
mon[Drift / Freshness 监控]
etl -.-> reg
online -.-> mon
end
Point-in-Time Join 的机制¶
目标:对每个训练样本 (user_id, event_ts),取 event_ts 那一刻的特征值。
-- PIT Join(最关键的技术,最容易写错)
SELECT
e.user_id,
e.event_ts,
e.label,
f.avg_7d_gmv
FROM events e
ASOF LEFT JOIN feature_view f
ON f.user_id = e.user_id
AND f.feature_ts <= e.event_ts -- 不能取未来
AND f.feature_ts > e.event_ts - INTERVAL '7 days' -- TTL
细节难点: - 时间粒度:特征更新 1 分钟一次 vs 1 天一次 - 缺失值:某 user 在 ts 之前没有 feature_ts → 怎么处理 - 效率:100 亿事件 × 100 个特征的 PIT Join 是性能噩梦 - 幂等性:同一 sample 多次计算结果必须一致
3. 关键机制¶
机制 1 · Materialization(离线→在线同步)¶
两种模式: - Batch Materialization(定时):每天 / 每小时 dump 到 Redis - Streaming Materialization(实时):Flink 持续写 Redis
机制 2 · Online Serving SLA¶
推理侧:
features = fs.get_online_features(
features=["user_fv:avg_7d_gmv", "user_fv:vip_level"],
entity_rows=[{"user_id": 12345}]
).to_dict()
延迟预算: - 单 entity 单次获取:< 10ms(Redis / Aerospike) - 批量 N 个 entity 获取:< 50ms(100 个) - 并发:几万 QPS 起步
机制 3 · 流式特征(On-Demand Features)¶
一些特征计算需要请求时实时参与:
# 用户 session 内的 clicked_items(来自 Kafka 近 10min)
session_clicks = fs.get_on_demand_features(
request={"user_id": 123, "timestamp": now},
feature_view="session_clicks_10min"
)
Flink 维护 state、FS 暴露 online lookup。
机制 4 · Feature Registry¶
不只是个目录——包含: - 定义(SQL / Python) - Owner(谁负责) - SLA(更新频率) - 血缘(从哪些源头算出来) - Drift 监控(分布变化告警) - 废弃流程(谁在用?能不能下线)
机制 5 · Drift 监控¶
离线特征 vs 在线特征的分布对齐:
| 指标 | 意义 |
|---|---|
| PSI(Population Stability Index) | < 0.1 稳定 · > 0.25 漂移 |
| KS 值 | 两分布差异 |
| Missing rate | 缺失率突变 |
| Feature Value mean / std | 均值方差变化 |
漂移 → 告警 → 可能是上游数据源变了 / 抽样偏差 / ETL 故障。
4. 工程细节¶
核心产品家族¶
详见 Feature Store 横比。实务选择:
| 需求 | 首选 |
|---|---|
| 开源 · 自运营 · 湖已就位 | Feast + Iceberg + Redis |
| 商业 SaaS · 要 SLA | Tecton |
| 合规 / 含完整 MLOps | Hopsworks |
| 全栈 Databricks / GCP / AWS | 对应云厂商托管 FS |
| 小团队 · < 100 特征 | 自建 Iceberg + Redis + dbt |
Feast 典型定义¶
# Feast 0.40+ API · value_type 已 deprecated · 改用 join_keys
from feast import Entity, FeatureView, Field, FileSource
from feast.types import Float32, Int64
from datetime import timedelta
user = Entity(name="user", join_keys=["user_id"])
user_source = FileSource(
path="s3://lake/features/user_stats.parquet",
timestamp_field="event_ts",
)
user_stats = FeatureView(
name="user_stats",
entities=[user],
ttl=timedelta(days=7),
schema=[
Field(name="avg_7d_gmv", dtype=Float32),
Field(name="purchase_7d", dtype=Int64),
Field(name="vip_level", dtype=Int64),
],
source=user_source,
online=True,
)
离线获取训练数据(PIT 自动处理)¶
entity_df = spark.sql("SELECT user_id, event_ts, label FROM train_events")
training_df = store.get_historical_features(
entity_df=entity_df,
features=[
"user_stats:avg_7d_gmv",
"user_stats:purchase_7d",
"user_stats:vip_level",
],
).to_df()
在线获取(推理)¶
features = store.get_online_features(
features=[
"user_stats:avg_7d_gmv",
"user_stats:vip_level",
],
entity_rows=[{"user_id": 12345}]
).to_dict()
score = model.predict(features)
Materialization(离线 → 在线)¶
典型调度:每小时跑一次,增量把过去一小时的特征值同步到 Redis。
5. 性能数字¶
以下数字为经验基线 [来源未验证 · 示意性 · 依硬件 / 数据 / 调优差异大 · 不要直接套用]。
Feast + Redis(典型规模)¶
| 指标 | 基线 |
|---|---|
| Online get_online_features(单 entity) | 2-10ms |
| Batch get_online_features(100 entity) | 20-50ms |
| 单 Feature View Registry 规模 | 数百 feature OK |
| PIT Join 性能(Spark · 硬件 / broadcast / 分区未声明) | 100M 样本 × 20 FV ≈ 30 分钟 |
| Materialization 吞吐 | 10k-100k rows/s |
Tecton 生产案例 [来源未验证 · 示意性 · 自测为准]¶
- 某推荐系统:3000+ features · 在线 p99 < 20ms · 50k QPS 级
- 某风控系统:实时特征延迟 < 2 分钟(Kafka → online store)
6. 代码示例¶
Feast 项目完整结构¶
my_project/
├── feature_repo/
│ ├── feature_store.yaml # 配置(online/offline store)
│ ├── entities.py
│ ├── data_sources.py
│ ├── feature_views.py
│ └── feature_services.py
└── airflow/
├── materialize_dag.py
└── drift_check_dag.py
feature_store.yaml¶
project: my_project
provider: aws
registry:
registry_type: sql
path: postgresql://...@feast-registry/db
online_store:
type: redis
connection_string: redis.internal:6379
offline_store:
type: file # 或 spark, bigquery, trino
path: s3://lake/features/
entity_key_serialization_version: 2
自建 Iceberg + Redis 最小闭环¶
# 1. dbt 定义特征(Iceberg 宽表)
# models/features/user_stats.sql
SELECT
user_id,
event_ts,
AVG(amount) OVER (PARTITION BY user_id ORDER BY event_ts
RANGE BETWEEN INTERVAL '7 days' PRECEDING AND CURRENT ROW)
AS avg_7d_gmv
FROM orders;
# 2. Spark 每小时物化到 Redis · 注意:redis client 必须在 executor 内初始化
# 直接在 lambda 里 capture driver 端的 client 会 pickle 失败 / 反模式
def write_partition(rows):
import redis
client = redis.Redis(host="redis.internal", port=6379)
pipe = client.pipeline()
for r in rows:
pipe.set(f"u:{r.user_id}:avg_7d_gmv", r.avg_7d_gmv)
pipe.execute()
spark.read.table("iceberg.features.user_stats").foreachPartition(write_partition)
# 3. 推理侧读 Redis
value = redis_client.get(f"u:{user_id}:avg_7d_gmv")
6.5 Vector-enabled Feature Store · 2025-2026 新趋势¶
2024 年以前 · Feature Store 和向量库是两套独立系统。2025+ 主流 FS 已经内置向量特征:
| 平台 | 向量能力 |
|---|---|
| Databricks Feature Store / Online Tables(2024) | 直接存 embedding 作 feature · Delta + 向量索引一体 |
| Tecton(2024+) | Vector feature · 内置 ANN 查询 |
| Hopsworks 4.x(2024-2025) | OpenSearch 后端 · vector + structured feature 混合 |
| Vertex AI Feature Store | Matching Engine 集成 |
为什么重要: - LLM 时代推理请求经常要同时拉"结构化特征"(用户画像 · 订单数 · VIP 等级)和向量特征(用户兴趣 embedding · 最近 N 个点击的 item embedding) - 两套系统 → 两个 client · 两个延迟来源 · 两套权限 · 训推对账翻倍复杂 - 一套 FS 接口 → LLM Agent / 推荐 / 风控 统一取数
代码示例(Tecton · 2024+)¶
# 结构化 + 向量 feature 一起取
features = tecton.get_online_features(
feature_service="user_llm_context",
join_keys={"user_id": 12345},
request_data={"query_embedding": query_vec}, # 在线 ANN
)
# 返回:{vip_level: 3, avg_7d_gmv: 580.2, similar_items: [...], ...}
6.6 Feature Store × LLM Agent · Tool 一等公民¶
LLM Agent(见 agents-on-lakehouse)执行复杂任务时 · 经常需要实时用户上下文:
- "帮用户查一下最近 3 天的订单" → Agent 调 FS
get_online_features(recent_orders) - "推荐一个新商品" → Agent 调 FS
get_online_features(user_embedding + vip_level + preferences) - "风险评估" → Agent 调 FS
get_online_features(risk_score + device_profile)
Agent Tool 对 FS 的要求: - 低延迟(<50ms · Agent 调用链里 FS 是一环) - 权限感知(Agent 代表具体用户查数据时 · FS 接口要传递 user identity · 不能读别人的特征) - Schema 可发现(Agent 动态决定调哪个 feature service · 需要 FS 暴露 registry / catalog) - 审计完整(Agent 每次 FS 调用要有 trace · 对应 llm-observability)
反模式:把 FS 当成"让 Agent 查所有数据"的通道 —— 应配 authorization §Tool ACL 严格限制 Agent 能读哪些 feature view。
6.7 何时不需要 Feature Store · Anti-pattern¶
Feature Store 是有成本的系统投资(在线 store 运维 · Registry 维护 · 团队学习曲线)。不是所有 ML 团队都该上。以下场景 Feature Store 是过度工程:
| 场景 | 理由 | 替代方案 |
|---|---|---|
| 模型数量少(1-5 个) | FS 的"特征复用"价值出不来 | 直接 SQL + pickle cache 够用 |
| 无在线推理 / 只跑批 | FS 在线 store 的主要价值浪费 | Iceberg / Parquet 离线表 + dbt 够用 |
| 特征重用极少(每模型各自算特征) | 跨模型复用是 FS 核心卖点 | 模型各自 feature pipe · 放 Iceberg 就行 |
| 特征更新频率低(天 / 周级) | 实时在线 store 无意义 | 定期批物化到 Redis · 不需要完整 FS |
| 团队维护能力薄弱(< 2 平台工程师) | 在线 store 故障 SRE 负担大 | 延后 FS · 先做 golden path |
| 数据还在 OLTP / 数仓 · 不在湖 | FS 要先落湖 · 路径长 | 先统一入湖 · 再考虑 FS |
| 跨数据源(湖 + 外部 API + 三方) | FS 不擅长非湖源 | 业务层自己拉 |
决策 checklist: 1. 有 5+ 个模型 共用 3+ 个特征? 2. 有在线推理且 p99 < 50ms 对特征延迟敏感? 3. 训推不一致是明确痛点(线上效果差于离线)? 4. 有 2+ 人可以投入 FS 维护?
≥ 3 个 Yes 才考虑上 Feature Store。否则用 "Iceberg + dbt + Redis 手工 materialize" 极简方案已经能解决 70% 需求。
6.8 Feature Store ROI 考量¶
不要把 FS 当成"成熟度标配"。FS 是有明确 ROI 门槛的系统投资:
- 投入:初期 1-2 人月 + 持续维护 0.5 人 · 工具费(Tecton SaaS)· 学习成本
- 产出:特征复用 · 训推一致 · 审计血缘 · 业务 KPI 提升
- ROI 可见期:通常 6-12 月 · 模型数量 < 5 时基本不见
- 隐性成本:团队思维模式切换(从"SQL 写特征"到"定义 FeatureView")
阶段性推荐: - 0-5 模型:先 Iceberg + dbt + Redis DIY · 积累特征定义 - 5-20 模型:Feast 开源栈 · 解决复用和训推一致 - 20+ 模型 · 或要求 SLA:Tecton / Databricks FS / Hopsworks
7. 陷阱与反模式¶
- 自建 FS 低估 PIT 复杂度:PIT Join 几乎是 Feature Store 事故 #1 原因
- 训推用不同代码:再强调一次——一定用同一套定义
- 离线在线不对账:至少每天跑一次抽样对比
- Feature TTL 不设:Redis 内存爆 / 过时特征喂模型
- Drift 不监控:模型悄悄劣化、业务来投诉才发现
- Schema 演化不管:加列删列影响在线,要有流程
- Feature 数量无限涨:500+ 特征谁在用、能不能下线 → 强治理
- Online Store 无副本:挂了 → 推理全瘫 → 主从或多活
- 流式特征没时序保证:Out-of-order events 错误聚合
- 训练 snapshot 不锁:明天重跑训练数据变了 → 模型不可复现
8. 横向对比 · 延伸阅读¶
- Feature Store 横向对比 —— Feast/Tecton/Hopsworks/云厂商/自建
- Feature Serving 场景 —— 在线侧细节
- 离线训练数据流水线 —— PIT 深入
- 推荐系统 · 欺诈检测
权威阅读¶
- Uber Michelangelo(2017) —— FS 工业首例
- Feast 官方文档 · Tecton 白皮书
- Hopsworks Feature Store 论文
- Designing Machine Learning Systems (Chip Huyen) —— 第 6 章详细讲 FS
- featurestore.org —— 社区汇总
相关¶
- RAG —— 姊妹基础设施(一个是"给 LLM 上下文",一个是"给 ML 特征")
- Embedding 流水线
- Feature Serving · 离线训练数据流水线
- 推荐系统 · 欺诈检测