4、数据格式选择:Avro、Parquet、ORC、JSON、CSV 的优劣对比与选型
数据格式选型这事儿,说实话,是很多团队容易忽视的坑。我见过不少项目,前期随便选了个格式,结果到了每天处理几十TB数据的时候,IO瓶颈直接把人逼疯。今天咱们就把这五种主流格式掰开揉碎聊清楚。
4.1 先看一张全景图
下面这张图是我自己总结的,把五种格式的核心定位和适用场景串在了一起。你一看就明白它们各自站在哪个位置。
4.2 五种格式逐个拆解
4.2.1 JSON — 灵活但昂贵
JSON 的好处是啥?人类可读,自描述,schema 可以随时变。我早期做日志采集的时候,第一版就用的 JSON,因为后端改字段太频繁了。
但代价也很明显:
- 体积大 — 同样的数据,JSON 比 Avro 大 3~5 倍
- 解析慢 — 每条记录都要做文本解析
- 无类型约束 — 数字可能被当成字符串
我的建议:JSON 只适合做数据源接入的临时格式,或者调试阶段。生产环境长期存储?千万别。
4.2.2 CSV — 简单但脆弱
CSV 可能是最古老的格式了。简单是真简单,随便一个文本编辑器就能打开。但坑也多:
- 字段里带逗号怎么办?带换行符怎么办?
- 没有类型信息,123 是数字还是字符串?
- 编码问题 — 我遇到过 UTF-8 和 GBK 混用,排查了一整天
避坑:我曾经把一个 CSV 文件直接导入 Hive,结果因为某个字段里藏了换行符,整个分区数据全乱了。从那以后,生产环境我坚决不用 CSV 做数据交换。
4.2.3 Avro — 行存之王
Avro 是我个人最喜欢的数据摄取格式。为什么?
- 行式存储 — 写一条记录就是一次顺序写,吞吐极高
- Schema 内嵌 — 每个文件自带 schema,自解释
- Schema 演进 — 支持向后/向前兼容,加字段不影响老数据
- 压缩率高 — 配合 snappy 或 zstd,体积能压到 JSON 的 1/5
看个 Avro schema 的例子:
{
"type": "record",
"name": "UserEvent",
"fields": [
{"name": "user_id", "type": "string"},
{"name": "event_time", "type": "long"},
{"name": "event_type", "type": "string"},
{"name": "payload", "type": ["null", "string"], "default": null}
]
}
注意那个 default: null,这就是 schema 演进的精髓。老数据没有这个字段,读的时候自动补 null。
适用场景:Kafka 消息、日志采集、数据管道中间环节。说白了,只要你是逐条写入的场景,Avro 就是最优解。
4.2.4 Parquet — 分析查询的利器
Parquet 是列式存储,跟 Avro 的思路完全相反。它不是为了写得快,而是为了读得快。
列存的优势在哪?
- 只读需要的列 — 比如一张表有 100 列,你只查 3 列,Parquet 只读那 3 列的数据
- 列内压缩 — 同一列的数据类型相同,压缩算法可以针对优化
- 谓词下推 — 支持 min/max 统计信息,跳过不必要的数据块
我记得有一次做用户画像分析,原始数据 2TB,用 Parquet 存完只有 400GB,查询时间从 20 分钟降到了 40 秒。这就是列存的威力。
4.2.5 ORC — Hive 生态的宠儿
ORC 跟 Parquet 类似,也是列存。但它跟 Hive 的绑定更深:
- 更细粒度的索引 — 支持 stripe 级别和行组级别的统计信息
- ACID 支持 — Hive 的事务操作需要 ORC
- 压缩率更高 — 在某些场景下比 Parquet 再省 10~20%
不过 ORC 在 Spark 和 Presto 里的支持度不如 Parquet 好。如果你用的是 Spark 生态,我建议优先选 Parquet。
4.3 核心对比表
| 维度 | JSON | CSV | Avro | Parquet | ORC |
|---|---|---|---|---|---|
| 存储方式 | 行存 | 行存 | 行存 | 列存 | 列存 |
| Schema 支持 | 自描述 | 无 | 强类型+演进 | 强类型 | 强类型 |
| 写入速度 | 中 | 快 | 快 | 慢 | 慢 |
| 读取速度(全列) | 慢 | 慢 | 中 | 快 | 快 |
| 读取速度(部分列) | 慢 | 慢 | 慢 | 极快 | 极快 |
| 压缩率 | 低 | 低 | 高 | 很高 | 很高 |
| 生态兼容性 | 全平台 | 全平台 | Hadoop/Kafka | Spark/Presto | Hive |
| 典型场景 | API 响应 | 临时导出 | 数据摄取 | 分析查询 | Hive 数仓 |
4.4 选型决策流程
说了这么多,到底怎么选?我一般按下面这个流程走:
- 先看场景 — 是数据摄取还是分析查询?
- 数据摄取阶段 → 选 Avro(行存,写快,schema 灵活)
- 分析查询阶段 → 选 Parquet(列存,读快,生态好)
- 临时/调试 → 选 JSON 或 CSV(方便肉眼检查)
- Hive 重度用户 → 选 ORC(ACID 和索引优势)
一个常见的生产架构:Kafka 里用 Avro 做消息序列化 → 数据落地到 HDFS 时转成 Parquet → 最终用 Presto/Spark 做分析查询。这个链路我用了三年,稳定可靠。
4.5 避坑指南
我曾经踩过的坑:
- 把 JSON 日志直接存 HDFS,半年后存储成本翻了三倍
- 用 CSV 做跨系统数据交换,字段顺序对不上导致数据错位
- 在 Spark 里用 ORC,发现某些聚合操作比 Parquet 慢 30%
最后说一句:没有银弹。每种格式都有它的位置,关键是搞清楚你当前阶段的核心矛盾是什么。是写入吞吐?是查询性能?还是存储成本?想清楚这个,选型就不难了。