特征存储选型:Redis、HBase、Cassandra、MongoDB 对比

特征存储选型,说白了就是给你的实时特征找个合适的家。我见过不少团队,一上来就拍脑袋用 Redis,结果到了线上发现内存撑不住;也见过迷信 HBase 的,结果延迟高得离谱。今天咱们把这四个主流选手拉出来遛遛。

核心观点:没有最好的存储,只有最合适的场景。选型前先问自己三个问题——延迟要求多高?数据量多大?读写比例是多少?

2.1 四个选手的定位速览

先给个直观印象。我习惯用一句话概括每个系统的性格:

  • Redis:纯内存战士,快得离谱,但贵得心疼。适合小数据量、高吞吐的热特征。
  • HBase:列式存储老炮,海量数据下的强一致。适合用户画像、历史行为这类大宽表。
  • Cassandra:分布式女王,天生多活。适合跨机房部署、写多读少的场景。
  • MongoDB:文档型万金油,Schema 灵活。适合特征结构经常变动的场景。

你想想看,这四个东西压根不是同一类产品。Redis 是缓存,HBase 是 NoSQL 数据库,Cassandra 是宽列存储,MongoDB 是文档数据库。硬要放在一起比,其实比的是「谁更适合做特征存储」。

2.2 核心维度对比

我一般从五个维度做选型评估。下面这张表是我自己整理的,每次做技术方案评审都拿出来对照:

维度 Redis HBase Cassandra MongoDB
读写延迟 <1ms(内存) 5-20ms(HDFS) 1-5ms(LSM-Tree) 1-10ms(WiredTiger)
数据容量 GB~TB(受内存限制) PB级(自动分片) PB级(一致性哈希) TB~PB级(分片集群)
读写模型 读多写少(最优) 读写均衡 写多读少(最优) 读写均衡
一致性 最终一致(集群) 强一致(单行) 可调一致 可调一致
运维复杂度 低(单机/哨兵) 高(依赖HDFS/ZK) 中(无中心) 中(分片需规划)

我的经验:延迟数字别只看官方 benchmark。我在项目中遇到过,Redis 在 100ms 网络延迟下照样崩。实际测一下你的网络拓扑,比看文档管用十倍。

2.3 场景分析:什么时候选谁?

场景一:实时特征缓存(Redis 的天下)

如果你做的是 CTR 预估,特征维度几千维,每条请求需要毫秒级返回。别犹豫,上 Redis。我做过一个广告推荐系统,用户特征全放 Redis,单机 QPS 能到 10 万+。

但要注意——Redis 不是数据库。我曾经犯过一个错:把全量用户画像塞进 Redis,结果 16GB 内存撑爆了。后来改成只缓存热数据,冷数据走 HBase,才稳住。

# 典型用法:用户实时特征
SET user:12345:features '{"age":28,"city":"北京","last_click":"2024-01-15"}'
EXPIRE user:12345:features 3600  # 1小时过期

# 批量读取(Pipeline)
redis.pipeline()
  .get('user:12345:features')
  .get('item:67890:embedding')
  .execute()

避坑指南:Redis 的过期策略是惰性+定期删除。如果你写入量太大,过期 key 可能堆积,导致内存泄漏。我建议主动设置 maxmemory-policy allkeys-lru,并监控内存水位。

场景二:海量用户画像(HBase 的强项)

用户画像表动辄几十亿行,每行几百个特征列。这种场景下,HBase 的列族设计天然适合。我做过一个金融风控项目,每个用户有 500+ 特征,用 HBase 存储,单行读取稳定在 10ms 以内。

为什么会选 HBase?因为它支持强一致性。特征更新后,下游立刻能读到最新值。这在风控场景里是刚需。

# HBase 表设计:用户画像
create 'user_profile', 'base', 'behavior', 'risk'

# 写入特征
put 'user_profile', 'user_12345', 'base:age', '28'
put 'user_profile', 'user_12345', 'behavior:last_7d_clicks', '1024'
put 'user_profile', 'user_12345', 'risk:score', '0.85'

# 读取整行
get 'user_profile', 'user_12345'

我的建议:HBase 的 RowKey 设计是门学问。别用用户 ID 直接做 RowKey,容易热点。我习惯加盐(salt),比如 user_12345 改成 05_user_12345,前缀用用户 ID 的哈希取模。

场景三:跨机房特征同步(Cassandra 的舞台)

如果你的业务覆盖全球,需要多活部署。Cassandra 的无中心架构就是天选之子。我参与过一个国际化推荐系统,欧洲、北美、东南亚各一套 Cassandra 集群,数据自动同步,延迟在 50ms 以内。

Cassandra 的写性能极其强悍。单节点每秒能写几万条,而且线性扩展。但读性能一般,尤其是范围查询——它本质上是个写优化的 LSM-Tree。

// Cassandra 表定义
CREATE TABLE user_features (
  user_id text,
  feature_name text,
  feature_value text,
  update_ts timestamp,
  PRIMARY KEY (user_id, feature_name)
) WITH compaction = {'class': 'LeveledCompactionStrategy'};

// 写入特征
INSERT INTO user_features (user_id, feature_name, feature_value, update_ts)
VALUES ('user_12345', 'age', '28', toTimestamp(now()));

避坑指南:Cassandra 的二级索引性能极差,千万别在生产环境用。我见过有人用二级索引做特征查询,结果一次查询扫了全表。正确的做法是:用主键查询,或者建物化视图。

场景四:动态特征结构(MongoDB 的灵活)

特征工程迭代快,今天加个 embedding,明天加个统计特征。如果用关系型数据库,改表结构能改到崩溃。MongoDB 的文档模型就舒服多了——字段随便加,不用跑 migration。

我做过一个实验性推荐项目,特征 Schema 每周都在变。用 MongoDB 存储,开发效率至少提升 50%。但要注意,MongoDB 的写入锁在 4.0 之前是库级别,高并发下容易阻塞。

// MongoDB 文档示例
{
  "_id": "user_12345",
  "base": {
    "age": 28,
    "city": "北京"
  },
  "behavior": {
    "last_7d_clicks": 1024,
    "last_30d_orders": 15
  },
  "embedding": [0.12, 0.45, 0.78, ...]  // 动态添加
}

// 更新特征(upsert)
db.user_features.updateOne(
  { _id: "user_12345" },
  { $set: { "embedding": [0.12, 0.45, 0.78] } },
  { upsert: true }
);

2.4 选型决策树

说了这么多,到底怎么选?我画了一张决策图,帮你快速定位:

特征存储选型决策树 特征存储选型 延迟 < 5ms? 延迟 > 5ms? 数据量 < 100GB 数据量 > 100GB Redis Redis + 冷存储 写多读少? 读写均衡? Cassandra HBase / MongoDB 说明: • 延迟 < 5ms 且数据量小 → Redis(热数据) • 延迟 < 5ms 且数据量大 → Redis 缓存 + 冷存储降级 • 延迟 > 5ms 且写多读少 → Cassandra(多活场景优先) • 延迟 > 5ms 且读写均衡 → HBase(强一致)或 MongoDB(灵活Schema)

2.5 混合存储架构

实际生产环境,很少只用一种存储。我见过最稳的架构是分层存储:

  • L1(热数据):Redis,存最近 1 小时活跃用户的特征,TTL 自动过期
  • L2(温数据):HBase/Cassandra,存全量用户画像,按天分区
  • L3(冷数据):HDFS/对象存储,存历史快照,用于离线训练

查询时先查 Redis,没命中再查 HBase,最后回写 Redis。这套方案我在两个项目里验证过,延迟和成本都控制得很好。

总结一下:选特征存储,先看延迟要求,再看数据量,最后看读写模式。别盲目追新,也别死守老技术。适合你的,就是最好的。