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):
    -- 对于 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.Lz4Codec
    
    当 Hive 使用 Spark 作为执行引擎时,Spark 自身的 Shuffle 压缩配置(如 spark.shuffle.compressspark.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 文件,ZSTDSnappy 是优秀的选择。ZSTD 提供更好的压缩比和不错的速度,Snappy 提供极致的速度和合理的压缩比。
  • 速度优先: SnappyLZ4,尤其适用于 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 的中间输出压缩配置,但目标相似。

9. 最佳实践

  1. 优先选择列式存储: 尽可能使用 ORC 或 Parquet 文件格式。它们本身就具有高效的编码方式,结合压缩能达到更好的效果,并且天然支持谓词下推和列裁剪,极大提升查询性能。
  2. 选择可分割的压缩: 对于大型数据集,务必确保最终存储的文件是可分割的。这意味着:
    • 如果使用 TextFile,避免 Gzip,可选择 Bzip2(慢)或不压缩,或者转换为 ORC/Parquet。
    • ORC 和 Parquet 总是可分割的,选择其内部压缩编解码器时主要考虑压缩比和速度的平衡 (如 ZSTD, Snappy)。
  3. 中间压缩: 始终启用中间数据压缩 (hive.exec.compress.intermediate=true),并选择快速的编解码器如 Snappy 或 LZ4,因为中间数据的生命周期短,读写速度是关键。
  4. 最终输出压缩: 根据数据访问频率和存储成本选择。
    • 热数据/频繁访问: Snappy, LZ4, ZSTD (低级别) 提供较好的读写性能。
    • 温数据/一般访问: ZSTD (中等级别), ZLIB (ORC默认) 是不错的平衡。
    • 冷数据/归档: Bzip2, Gzip (用于小文件或非并行场景), ZSTD (高级别) 提供高压缩比。
  5. 测试与监控: 不同的数据集和工作负载对压缩的响应不同。建议在实际环境中测试不同的压缩编解码器和文件格式组合,监控 CPU 使用率、I/O 带宽、存储空间和查询响应时间,以找到最佳平衡点。
  6. 小文件问题: 压缩虽然能减少文件大小,但如果原始文件就很小,压缩后可能依然是小文件。要结合小文件合并策略(如 Hive 的 hive.merge.mapfiles=true, hive.merge.mapredfiles=true, hive.merge.tezfiles=true)来管理。
  7. 考虑数据特性:
    • 文本类数据通常有较高的压缩潜力。
    • 已经高度压缩或随机的数据(如加密数据、某些二进制格式)可能压缩效果不佳,甚至可能因压缩开销而降低性能。
  8. 确保编解码器可用: 在集群的所有节点上安装并正确配置 Hadoop (core-site.xml 中的 io.compression.codecs) 以支持所需的编解码器。LZO 等可能需要额外安装本地库。

10. 结论

Hive 中的数据压缩是优化存储和查询性能的关键环节。理解不同压缩编解码器的特性、如何在 Hive 中配置它们以及它们与不同文件格式的交互方式,对于数据工程师和管理员至关重要。通过结合使用高效的列式存储格式(ORC, Parquet)和合适的压缩策略(如 ZSTD 或 Snappy),可以显著提升 Hive 数据仓库的效率和成本效益。务必根据具体的数据特性、访问模式和性能要求进行测试和选择。

posted @ 2025-08-12 10:24  magic_guan  阅读(159)  评论(0)    收藏  举报