数据存储与分区:从原始数据到可分析资产
大家好,欢迎来到第二章。上一章我们聊了全链路管理的整体视图,今天要扎进一个非常具体、也非常关键的话题——数据存储与分区。
说实话,我见过太多团队在模型训练上花了大把精力,结果发现数据准备阶段就埋了雷。要么存储选型不对,跑个查询要等半天;要么分区策略混乱,数据工程师天天在修分区边界。嗯,这些坑我都踩过。今天咱们就把这块掰开揉碎了讲清楚。
数据湖 vs 数据仓库:别再傻傻分不清
先问个问题:你手头的数据,到底该放湖里还是放仓里?
很多人觉得这俩概念差不多,其实差别大了去了。我个人的理解是——数据湖存的是"原材料",数据仓库存的是"半成品"。
| 维度 | 数据湖 | 数据仓库 |
|---|---|---|
| 数据格式 | 原始格式(CSV、JSON、日志、图片) | 结构化/半结构化(Parquet、ORC) |
| Schema | 读时模式(Schema-on-Read) | 写时模式(Schema-on-Write) |
| 主要用途 | 探索、数据科学、机器学习 | BI报表、固定查询、业务分析 |
| 数据质量 | 较低,允许脏数据 | 较高,经过清洗转换 |
| 典型技术 | HDFS、S3、ADLS、MinIO | ClickHouse、Snowflake、Redshift |
我在一个电商项目中遇到过这样的情况:业务方想分析用户行为路径,数据仓库里只有聚合后的订单表,根本没法做序列分析。后来我们把原始点击日志直接丢进数据湖,用Spark跑一遍,问题就解决了。说白了,数据湖给了你"后悔"的权利——原始数据还在,随时可以重新加工。
核心原则:数据湖存"原样",数据仓库存"有用"。两者不是替代关系,是上下游关系。
HDFS vs 对象存储:选型背后的门道
聊完湖和仓,接下来就是底层存储选型了。目前主流就两派:HDFS 和对象存储(S3、OSS、MinIO 之类的)。
我记得刚入行那会儿,HDFS 几乎是唯一选择。但近几年对象存储越来越火,甚至有些团队直接把 HDFS 换掉了。为什么会这样?
HDFS 的优势与局限
- 强一致性:写入后立即可见,适合需要严格一致性的场景
- 本地计算亲和性:数据本地化调度,减少网络开销
- 但……扩展性受限,NameNode 是单点瓶颈;运维成本高,集群挂了恢复很痛苦
对象存储的优势与局限
- 无限扩展:理论上存储容量无上限,按量付费
- 高可用:多副本、跨区域复制,基本不用操心运维
- 但……最终一致性(某些场景下会有延迟);计算和存储分离,网络开销大
我的建议:如果团队规模小、运维能力弱,优先选对象存储。如果对延迟和一致性要求极高,或者有大量本地计算任务,HDFS 仍然有它的位置。我在一个广告推荐项目中用过 S3 + Spark 的组合,效果不错,但要注意调整 shuffle 策略来减少网络传输。
分区策略:时间分区 vs 业务分区
存储选型定了,接下来就是怎么组织数据。分区策略做得好,查询效率能提升一个数量级。做不好……嗯,我曾经见过一个表有 2000 多个分区,每次查询都要扫全表。
分区策略主要分两种:时间分区和业务分区。实际项目中通常是两者结合。
时间分区
按日期、小时甚至分钟来划分数据。这是最常用的方式,因为大部分数据都有时间属性。
-- 按天分区示例(Hive SQL)
CREATE TABLE user_behavior (
user_id STRING,
action STRING,
page_url STRING
)
PARTITIONED BY (dt STRING)
STORED AS PARQUET;
-- 查询某天的数据
SELECT * FROM user_behavior WHERE dt = '2024-03-15';
时间分区的粒度怎么定?我个人的经验是:日分区是默认选择。小时分区适合数据量极大且查询频繁的场景,但分区数会膨胀得很快。分钟级分区?除非你有特殊需求,否则别碰。
业务分区
按业务维度划分,比如地域、产品线、用户等级等。
-- 业务分区示例
CREATE TABLE sales_data (
order_id STRING,
amount DOUBLE,
product_id STRING
)
PARTITIONED BY (region STRING, year STRING)
STORED AS ORC;
业务分区有个坑:分区键的选择要谨慎。我曾经有个项目,按"城市"分了 300 多个分区,结果小城市的数据只有几条记录,查询时反而增加了元数据开销。后来改成了按"省份"分区,效果好了很多。
避坑指南:分区不是越多越好。每个分区都会产生元数据,分区数超过 10000 后,NameNode 或对象存储的元数据服务会承受巨大压力。我曾经见过一个极端案例——分区数超过 5 万,查询计划生成就要花 30 秒。
列式存储:Parquet 与 ORC 的较量
最后聊聊文件格式。如果你还在用 CSV 或 JSON 存分析数据,我建议你立刻停下来。列式存储才是数据仓库和分析场景的正确姿势。
为什么列式存储快?说白了,它只读取你需要的列。比如你有一个 100 列的表,但只查其中 3 列,列式存储只需要读那 3 列的数据。行式存储呢?得把整行都读出来,再过滤掉不需要的列。你想想看,这差距有多大。
| 特性 | Parquet | ORC |
|---|---|---|
| 压缩率 | 高(支持多种编码) | 更高(轻量级索引 + 字典编码) |
| 读取性能 | 优秀(谓词下推支持好) | 优秀(内置索引,跳过无效数据更快) |
| 写入性能 | 中等 | 较好(批量写入优化) |
| 生态兼容性 | 极广(Spark、Hive、Presto、Trino 等) | 较广(Hive、Spark 支持,部分引擎需适配) |
| 适用场景 | 通用分析、数据湖 | Hive 重度用户、高压缩需求 |
我在一个日志分析项目中做过对比:同样的 10TB 数据,CSV 格式占用 12TB,换成 Parquet 后压缩到 1.8TB,查询速度提升了 8 倍。ORC 的压缩率更高,但当时我们的计算引擎对 ORC 的支持不够好,所以选了 Parquet。
选型建议:如果你的技术栈以 Spark 为主,Parquet 是更稳妥的选择。如果重度使用 Hive,ORC 的索引优势会更明显。两者都是好格式,选一个你团队最熟悉的就好。
知识体系总览
说了这么多,我画了一张图帮你把今天的内容串起来。这张图展示了从数据源到最终分析的全链路存储架构。
这张图把今天的内容串成了一个完整链路:数据源进来后,先选存储(HDFS 或对象存储),再决定是放湖里还是仓里,然后设计分区策略,最后用列式格式落地。每一步都有取舍,没有银弹。