Hive 压缩方式介绍与使用
Hive 压缩方式介绍与使用
1. 引言
在大数据生态系统中,Apache Hive 是一个常用的数据仓库工具。由于 Hive 处理的数据量通常非常庞大,数据压缩显得至关重要。压缩不仅可以显著减少存储空间,还能降低 I/O 开销,从而加快数据传输和查询处理速度。然而,不同的压缩算法在压缩比、CPU 开销、压缩/解压速度以及是否可分割等方面有所不同,选择合适的压缩方式对于 Hive 的性能优化至关重要。本文将详细介绍 Hive 支持的各种压缩方式、它们的特性、配置方法、使用场景及最佳实践。
2. Hive 支持的压缩编解码器 (Codec)
Apache Hive 自身不实现压缩算法,而是通过 Hadoop 的编解码器框架来支持各种压缩格式。常见的支持编解码器包括:
- Gzip (Deflate): 基于 DEFLATE 算法,提供较好的压缩比。
- Snappy: Google 开发,旨在提供非常高的压缩/解压速度和合理的压缩率。
- LZO (Lempel-Ziv-Oberhumer): 注重解压速度,压缩率和速度介于 Gzip 和 Snappy 之间。
- Bzip2: 提供比 Gzip 更高的压缩比,但压缩/解压速度慢,CPU 开销大。
- LZ4: 压缩/解压速度极快,通常比 Snappy 更快,压缩比略低于 Snappy。
- ZSTD (Zstandard): Facebook 开发,旨在提供类似 Gzip 的压缩比,但压缩和解压速度快得多。
- Zlib (Deflate): 与 Gzip 类似,是 DEFLATE 算法的一种实现,常作为 ORC 文件格式的默认压缩。
3. 常用压缩编解码器特性详解
| 特性 | Gzip (Deflate) | Snappy | LZO | Bzip2 | LZ4 | ZSTD |
|---|---|---|---|---|---|---|
| 压缩比 | 高 | 中 | 中 | 非常高 | 中 | 高 (可调) |
| 压缩速度 | 慢 | 非常快 | 快 | 非常慢 | 非常快 | 快 (可调) |
| 解压速度 | 中 | 非常快 | 非常快 | 非常慢 | 非常快 | 非常快 |
| CPU 开销 | 中高 | 低 | 低 | 非常高 | 低 | 中低 (可调) |
| 可分割性 | 否 | 否 (原始流)1 | 是 (需索引)2 | 是 | 否 (原始流)1 | 否 (原始流)1 |
1: Snappy, LZ4, ZSTD 的原始压缩流本身不可分割。但当它们用于压缩诸如 ORC, Parquet, SequenceFile (块压缩) 等文件格式的内部块时,这些文件格式自身支持按块/条带分割,从而实现整体文件的可分割性。
2: LZO 文件本身作为普通压缩文件时不可分割。但在 Hadoop 中,如果 LZO 文件被特殊工具(如lzo_indexer)创建了索引文件 (.lzo.index),则 MapReduce/Tez/Spark 可以根据索引进行文件分割。
3.1 Gzip (基于 DEFLATE 算法)
- 优点: 压缩比较高,通用性好。
- 缺点: 压缩/解压速度相对较慢,CPU 开销较大,不可分割。
- 适用场景: 适合于对存储空间有较高要求的冷数据归档,或数据量不大、不需要并行处理的场景。由于其不可分割性,在 MapReduce/Tez/Spark 中处理大型 Gzip 文件时,通常整个文件只能由一个任务处理,影响并行度。
3.2 Snappy
- 优点: 极高的压缩和解压速度,CPU 开销非常低。
- 缺点: 压缩比中等,低于 Gzip 和 ZSTD。原始 Snappy 流不可分割。
- 适用场景: 对读写性能要求高的场景,如热数据、中间数据压缩。在 ORC 和 Parquet 文件格式中广泛使用,此时文件格式保证了可分割性。
3.3 LZO
- 优点: 解压速度非常快,压缩速度也较快,CPU 开销较低。当配合索引使用时可分割。
- 缺点: 压缩比中等。需要额外生成索引文件才能在 Hadoop 中良好地分割。其许可模式(GPL)有时也限制了其在某些商业发行版中的直接集成。
- 适用场景: 曾经是需要速度和可分割性的热门选择,尤其是在 TextFile 格式下。
3.4 Bzip2
- 优点: 压缩比非常高,通常优于 Gzip。文件本身是可分割的。
- 缺点: 压缩和解压速度都非常慢,CPU 开销极大。
- 适用场景: 存储成本是首要考虑因素的归档场景,且对查询性能要求不高。
3.5 LZ4
- 优点: 压缩和解压速度极快,通常比 Snappy 更快,CPU 开销非常低。
- 缺点: 压缩比与 Snappy 相似或略低。原始 LZ4 流不可分割。
- 适用场景: 与 Snappy 类似,追求极致的读写速度,适用于中间数据或性能敏感的热数据。在 ORC 和 Parquet 中使用时,文件格式保证可分割性。
3.6 ZSTD
- 优点: 提供了类似 Gzip 的高压缩比,但压缩和解压速度(尤其是解压)快得多。压缩级别可调,允许在压缩比和速度之间进行权衡。
- 缺点: 相比 Snappy/LZ4,在追求极致速度时略逊一筹,但压缩比更高。
- 适用场景: 现代大数据存储的优秀选择,很好地平衡了压缩比和性能。推荐用于 ORC 和 Parquet 文件,是 Gzip 的一个良好替代品。
4. Hive 中的压缩配置
4.1 中间数据压缩 (MapReduce/Tez Shuffle)
Hive 查询在执行过程中可能会产生大量的中间数据(例如 Map 阶段的输出)。对中间数据进行压缩可以减少磁盘 I/O 和网络传输,从而提高作业性能。
- 启用中间压缩:
SET hive.exec.compress.intermediate=true; - 选择中间压缩编解码器 (通常选择速度较快的,如 Snappy 或 LZ4):
当 Hive 使用 Spark 作为执行引擎时,Spark 自身的 Shuffle 压缩配置(如-- 对于 MapReduce 和 Tez 引擎 (Tez 通常会识别这些 MapReduce 属性) SET mapreduce.map.output.compress=true; SET mapreduce.map.output.compress.codec=org.apache.hadoop.io.compress.SnappyCodec; -- 或 org.apache.hadoop.io.compress.Lz4Codecspark.shuffle.compress和spark.io.compression.codec)会生效。
4.2 最终输出数据压缩
对 Hive 表的最终存储文件进行压缩可以节省 HDFS 空间并加快后续查询的 I/O 速度。
- 启用最终输出压缩:
SET hive.exec.compress.output=true; - 选择最终输出编解码器 (根据具体文件格式和需求选择):
-- 对于 TextFile 和 SequenceFile,通常设置以下 Hadoop 参数 SET mapreduce.output.fileoutputformat.compress=true; SET mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.GzipCodec; -- 或 SnappyCodec, BZip2Codec, ZStandardCodec 等
4.3 特定文件格式的压缩配置
4.3.1 TextFile 和 SequenceFile
TextFile 和 SequenceFile 的压缩主要通过上述通用的 Hadoop MapReduce 输出参数控制。
- TextFile:
-- 创建压缩的 TextFile 表 (Gzip 压缩) SET hive.exec.compress.output=true; SET mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.GzipCodec; CREATE TABLE my_text_table (col1 INT, col2 STRING) STORED AS TEXTFILE; -- 插入数据时会以 Gzip 压缩 INSERT OVERWRITE TABLE my_text_table SELECT key, value FROM source_table; - SequenceFile:
-- 创建压缩的 SequenceFile 表 (Snappy 块压缩) SET hive.exec.compress.output=true; SET mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.SnappyCodec; SET mapreduce.output.fileoutputformat.compress.type=BLOCK; -- 对于 SequenceFile, 可选 RECORD 或 BLOCK (BLOCK 通常更好) CREATE TABLE my_sequence_table (col1 INT, col2 STRING) STORED AS SEQUENCEFILE; -- 插入数据时会以 Snappy 块压缩 INSERT OVERWRITE TABLE my_sequence_table SELECT key, value FROM source_table;
4.3.2 ORC (Optimized Row Columnar)
ORC 文件格式有其内部的压缩机制,通常通过表属性(TBLPROPERTIES)或 Hive 配置参数进行控制。ORC 默认使用 ZLIB 压缩。
- 通过
TBLPROPERTIES设置 (推荐):CREATE TABLE my_orc_table ( id INT, name STRING ) STORED AS ORC TBLPROPERTIES ("orc.compress"="SNAPPY"); -- 可选: NONE, ZLIB, SNAPPY, LZO, LZ4, ZSTD - 通过 Hive 配置参数设置 (会影响当前会话后续创建的所有 ORC 表,除非表属性覆盖):
SET hive.exec.orc.default.compress=SNAPPY; CREATE TABLE another_orc_table (col INT) STORED AS ORC; -- 此表默认使用 SNAPPY
ORC 文件格式会将数据分割成条带(stripes),每个条带内的数据可以独立压缩,因此 ORC 文件总是可分割的,无论内部使用何种压缩编解码器。
4.3.3 Parquet
Parquet 文件格式也支持内部压缩,通过表属性或配置参数指定。
- 通过
TBLPROPERTIES设置 (推荐):CREATE TABLE my_parquet_table ( id INT, name STRING ) STORED AS PARQUET TBLPROPERTIES ("parquet.compression"="SNAPPY"); -- 可选: UNCOMPRESSED, SNAPPY, GZIP, LZO, BROTLI, LZ4, ZSTD - 通过 Hive/Spark 配置参数设置:
Hive 通常会尊重TBLPROPERTIES。如果通过 Spark SQL 操作 Hive 表,Spark 的参数如spark.sql.parquet.compression.codec(默认snappy) 可能会生效。-- 在 Hive 中,通常 TBLPROPERTIES 是主要方式 -- 在 Spark SQL 中写 Hive Parquet 表时,可以用 Spark 的配置 -- SET spark.sql.parquet.compression.codec=gzip; (此为 Spark 配置,非 Hive 直接配置最终输出)
与 ORC 类似,Parquet 文件将数据组织成行组(row groups)和列块(column chunks),压缩作用于这些块,因此 Parquet 文件也是可分割的。
5. 关于文件可分割性 (Splittability) 的进一步说明
文件的可分割性是指 Hadoop MapReduce 或其他计算引擎(如 Tez, Spark)能否将一个大文件逻辑上切分成多个部分(splits),并分配给不同的任务并行处理。这对并行处理大规模数据集至关重要。
- 不可分割的文件: 例如,一个使用 Gzip 压缩的普通文本文件(
*.txt.gz)。如果文件很大,整个文件通常只能由一个 map 任务处理,这会成为性能瓶颈,无法利用集群的并行处理能力。 - 可分割的文件:
- 本身支持分割: Bzip2 文件内部有同步标记,允许从任意块边界开始读取。
- 通过外部索引分割: LZO 文件本身不可分割,但可以通过
lzo_indexer生成.lzo.index文件后实现分割。 - 容器文件格式 (ORC, Parquet, SequenceFile 块压缩): 这些文件格式将数据组织成内部的块/条带/行组。压缩是针对这些内部结构进行的。文件格式本身负责元数据管理,使得引擎可以定位到这些内部块的边界并独立处理它们。因此,即使内部块使用了像 Snappy 这种原始流不可分割的编解码器,整个 ORC 或 Parquet 文件仍然是可分割的。
核心观点: 对于面向列的存储格式 ORC 和 Parquet,它们总是可分割的,无论内部使用何种压缩编解码器。对于 TextFile,其可分割性取决于外部压缩编解码器(Gzip 使其不可分割,Bzip2 使其可分割)。
6. 压缩编解码器对比与选择建议
| 编解码器 | 主要优点 | 主要缺点 | 适用场景 (Hive 中) |
|---|---|---|---|
| Gzip | 压缩比高,通用 | 压缩/解压慢,CPU消耗高,不可分割 (用于 TextFile) | 冷数据归档 (若文件小或不追求并行度),ORC/Parquet 内部可选 (但不常推荐因有更好选择) |
| Snappy | 极快的压缩/解压速度,CPU消耗低 | 压缩比中等 | 中间数据压缩,热数据读写,ORC/Parquet 内的主流选择之一 (速度优先) |
| LZO | 快速的压缩/解压速度 (尤其解压),CPU消耗低 | 压缩比中等,用于 TextFile 需额外索引实现分割 | 曾用于 TextFile (需索引),ORC/Parquet 内部可选,但 Snappy/LZ4/ZSTD 更常见 |
| Bzip2 | 非常高的压缩比,可分割 (用于 TextFile) | 极慢的压缩/解压速度,CPU消耗非常高 | TextFile 的归档场景 (空间优先,能忍受极慢速度),ORC/Parquet 内部一般不使用 |
| LZ4 | 极快的压缩/解压速度 (通常比 Snappy 更快),CPU低 | 压缩比中等 | 中间数据压缩,热数据读写 (速度优先),ORC/Parquet 内部可选 |
| ZSTD | 高压缩比 (通常优于 Gzip),快速的解压速度 | 压缩速度依赖级别,比 Snappy/LZ4 略慢 | ORC/Parquet 的优秀选择 (平衡压缩比与性能),Gzip 的良好替代者 |
选择建议:
- 平衡性能与空间 (推荐): 对于 ORC 和 Parquet 文件,ZSTD 和 Snappy 是优秀的选择。ZSTD 提供更好的压缩比和不错的速度,Snappy 提供极致的速度和合理的压缩比。
- 速度优先: Snappy 或 LZ4,尤其适用于 MapReduce/Tez 的中间数据压缩。
- 空间优先:
- Bzip2: 用于极少访问的归档数据 (如 TextFile 格式),且文件可分割。
- Gzip: 如果 TextFile 文件较小或不需要并行处理,也可考虑。
- ZSTD (高级别): 用于 ORC/Parquet,可获得高压缩比同时保持可接受的性能。
- 避免: 尽量避免对大型 TextFile 使用 Gzip 压缩,因其不可分割性会严重影响查询性能。如果必须使用 TextFile 且需要压缩,考虑 Bzip2(如果能接受其速度)或将数据转换为 ORC/Parquet。
7. 关键 Hive 配置参数总结
hive.exec.compress.intermediate=[true|false]: (默认false) 是否压缩 MapReduce/Tez 作业的中间输出。推荐设置为true。mapreduce.map.output.compress.codec=<codec_class_name>: 指定中间数据压缩使用的编解码器(例如org.apache.hadoop.io.compress.SnappyCodec)。需配合mapreduce.map.output.compress=true。hive.exec.compress.output=[true|false]: (默认false) 是否压缩最终作业输出(写入 HDFS 的文件)。推荐设置为true。mapreduce.output.fileoutputformat.compress.codec=<codec_class_name>: 指定最终输出压缩使用的编解码器(用于 TextFile, SequenceFile)。需配合mapreduce.output.fileoutputformat.compress=true。mapreduce.output.fileoutputformat.compress.type=[NONE|RECORD|BLOCK]: 对于 SequenceFile,指定压缩类型(BLOCK压缩通常更好,也更利于分割)。- 表级别属性 (TBLPROPERTIES):
orc.compress=<NONE|ZLIB|SNAPPY|LZO|LZ4|ZSTD>: 为 ORC 表指定压缩编解码器。parquet.compression=<UNCOMPRESSED|SNAPPY|GZIP|LZO|BROTLI|LZ4|ZSTD>: 为 Parquet 表指定压缩编解码器。
hive.exec.orc.default.compress=<codec_name>: Hive 中 ORC 文件的默认压缩编解码器 (默认ZLIB)。io.compression.codecs: Hadoop 配置 (core-site.xml),列出集群中可用的编解码器。确保所需的编解码器已安装并在此列出。
8. 执行引擎的考量 (MapReduce, Tez, Spark)
- MapReduce: 上述
mapreduce.*和mapred.*(旧版) 参数直接适用。 - Tez: 作为 Hive 的默认执行引擎 (新版本中),Tez 通常会兼容并使用为 MapReduce 设置的压缩相关参数 (
mapreduce.map.output.compress.*,mapreduce.output.fileoutputformat.compress.*) 来处理中间和最终输出。Tez 自身也针对 I/O 进行了优化。 - Spark: 当 Hive on Spark 运行时:
- 对于 Spark SQL 写入 Hive 表 (尤其是 Parquet/ORC),Spark 自身的配置如
spark.sql.parquet.compression.codec(默认 snappy) 或spark.sql.orc.compression.codec(默认 snappy) 可能会覆盖或优先于 Hive 的设置。TBLPROPERTIES中的设置通常仍被尊重。 - Spark 的 Shuffle 操作(类似 MapReduce 的中间数据传输)有其自身的压缩配置,如
spark.shuffle.compress(默认 true) 和spark.io.compression.codec(默认 lz4 或 snappy,取决于 Spark 版本)。这些独立于 Hive 的中间输出压缩配置,但目标相似。
- 对于 Spark SQL 写入 Hive 表 (尤其是 Parquet/ORC),Spark 自身的配置如
9. 最佳实践
- 优先选择列式存储: 尽可能使用 ORC 或 Parquet 文件格式。它们本身就具有高效的编码方式,结合压缩能达到更好的效果,并且天然支持谓词下推和列裁剪,极大提升查询性能。
- 选择可分割的压缩: 对于大型数据集,务必确保最终存储的文件是可分割的。这意味着:
- 如果使用 TextFile,避免 Gzip,可选择 Bzip2(慢)或不压缩,或者转换为 ORC/Parquet。
- ORC 和 Parquet 总是可分割的,选择其内部压缩编解码器时主要考虑压缩比和速度的平衡 (如 ZSTD, Snappy)。
- 中间压缩: 始终启用中间数据压缩 (
hive.exec.compress.intermediate=true),并选择快速的编解码器如 Snappy 或 LZ4,因为中间数据的生命周期短,读写速度是关键。 - 最终输出压缩: 根据数据访问频率和存储成本选择。
- 热数据/频繁访问: Snappy, LZ4, ZSTD (低级别) 提供较好的读写性能。
- 温数据/一般访问: ZSTD (中等级别), ZLIB (ORC默认) 是不错的平衡。
- 冷数据/归档: Bzip2, Gzip (用于小文件或非并行场景), ZSTD (高级别) 提供高压缩比。
- 测试与监控: 不同的数据集和工作负载对压缩的响应不同。建议在实际环境中测试不同的压缩编解码器和文件格式组合,监控 CPU 使用率、I/O 带宽、存储空间和查询响应时间,以找到最佳平衡点。
- 小文件问题: 压缩虽然能减少文件大小,但如果原始文件就很小,压缩后可能依然是小文件。要结合小文件合并策略(如 Hive 的
hive.merge.mapfiles=true,hive.merge.mapredfiles=true,hive.merge.tezfiles=true)来管理。 - 考虑数据特性:
- 文本类数据通常有较高的压缩潜力。
- 已经高度压缩或随机的数据(如加密数据、某些二进制格式)可能压缩效果不佳,甚至可能因压缩开销而降低性能。
- 确保编解码器可用: 在集群的所有节点上安装并正确配置 Hadoop (
core-site.xml中的io.compression.codecs) 以支持所需的编解码器。LZO 等可能需要额外安装本地库。
10. 结论
Hive 中的数据压缩是优化存储和查询性能的关键环节。理解不同压缩编解码器的特性、如何在 Hive 中配置它们以及它们与不同文件格式的交互方式,对于数据工程师和管理员至关重要。通过结合使用高效的列式存储格式(ORC, Parquet)和合适的压缩策略(如 ZSTD 或 Snappy),可以显著提升 Hive 数据仓库的效率和成本效益。务必根据具体的数据特性、访问模式和性能要求进行测试和选择。

浙公网安备 33010602011771号