特征存储选型: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 选型决策树
说了这么多,到底怎么选?我画了一张决策图,帮你快速定位:
2.5 混合存储架构
实际生产环境,很少只用一种存储。我见过最稳的架构是分层存储:
- L1(热数据):Redis,存最近 1 小时活跃用户的特征,TTL 自动过期
- L2(温数据):HBase/Cassandra,存全量用户画像,按天分区
- L3(冷数据):HDFS/对象存储,存历史快照,用于离线训练
查询时先查 Redis,没命中再查 HBase,最后回写 Redis。这套方案我在两个项目里验证过,延迟和成本都控制得很好。
总结一下:选特征存储,先看延迟要求,再看数据量,最后看读写模式。别盲目追新,也别死守老技术。适合你的,就是最好的。