Hadoop 压缩从理论到实战

1. Background

在大数据领域,无论上层计算引擎采用的是什么,在存储过程中,压缩都是一个避不开的问题。合适的压缩选择可以降低存储成本、减少网络传输I/O。而错误的压缩选择则可能让 cpu 负荷达到瓶颈、降低并发度等等,所以是否选择压缩、选择什么压缩格式在大数据存储环节中都是一个至关重要的问题。

2. Basic

2.1 评判压缩算法的三个指标

  1. 压缩/解压时间
  2. 压缩率
  3. 是否支持分片(不能脱离压缩依附的存储格式讨论,后续详述)

点评:压缩时间和压缩率之间的取舍本质上是 cpu 资源和存储资源的取舍。是否需要支持分片也不是绝对的,如果单个文件大小均小于 splitSize,则没必要支持分片。

2.2 使用压缩的三个阶段

  1. Map 任务前的输入文件压缩
  2. Map 任务后,Reduce 任务前,Map 任务的输出文件压缩
  3. Reduce 任务后的输出文件压缩

点评:一阶段考虑尽可能支持分片(单个文件大于 splitSize 时)。二阶段考虑尽可能快的压缩速度。三阶段根据是作为长期归档(几乎不用)or 作为下一作业输入,考虑尽可能高的压缩能力 or 支持分片。

2.3 常见压缩格式及特点

  • gzip:压缩率比较高,但没有 snappy,lzo 速度那么快,不支持 split
  • zlib: 和 gzip 基本一样
  • lzo: 速度很快,压缩率合理。默认不支持 split,通过配置索引可以支持 split
  • lz4: 速度很快,压缩率合理。默认不支持 split,通过额外添加 4MC 库来支持 split
  • snappy: 速度最快,压缩率合理。不支持 split
  • bzip2: 最高压缩率,但是速度很慢。支持 split

点评:有两点需要注意,第一点:这里的速度和压缩率没有具体测试数据,而是给出了一个模糊的表达。因为即使具体测试了速度和压缩率,也会因数据不同而结果有很大的差异。后面会给出测试的脚本,大家可以结合自己的表数据自行测试。第二点:有些压缩格式性能参数很相似,为什么 Hadoop 中要搞这么多种?较为直观的一个原因是:不同存储格式支持的压缩是不一样的,比如 orc 存储格式只支持 zlib 和 snappy 两种压缩[8],parquet 虽然支持很多压缩格式,但是不支持 bzip2 [7]

2.4 什么是所谓的 splittable ?

以下摘自《Hadoop The Definitive Guide》

Lets assume we have a file of 1 GB size in HDFS whose block size is 64 MB. Which implies the file is stored in 16 blocks. The MapReduce job using this file as input will create 16 input splits, each processed independently as input to a separate map task.

Imagine now the file is a gzip-compressed file whose compressed size is 1 GB. As before, HDFS will store the file as 16 blocks. However, creating a split for each block won’t work since it is impossible to start reading at an arbitrary point in the gzip stream and therefore impossible for a map task to read its split independently of the others. The gzip format uses DEFLATE to store the compressed data, and DEFLATE stores data as a series of compressed blocks. The problem is that the start of each block is not distinguished in any way that would allow a reader positioned at an arbitrary point in the stream to advance to the beginning of the next block, thereby synchronizing itself with the stream. For this reason, gzip does not support splitting.

In this case, MapReduce will do the right thing and not try to split the gzipped file, since it knows that the input is gzip-compressed (by looking at the filename extension) and that gzip does not support splitting. This will work, but at the expense of locality: a single map will process the 16 HDFS blocks, most of which will not be local to the map. Also, with fewer maps, the job is less granular, and so may take longer to run.

重点阅读文中加粗片段。大致意思是:因为 gzip 压缩格式使用的 DEFLATE 压缩算法没办法做到随机任意读取,必须同步顺序读取。也就意味着没办法为每一个 block 创建一个分片(split),然后为该分片启一个 mapper 去读取数据。所以即使 gzip 文件有很多 block,MR 程序也只会启动一个 Mapper 去读取所有的 block。也即 gzip 这种压缩格式不支持分片。相反的,如果压缩格式使用的算法支持随机任意读取,那么就可以为每一个 block 创建一个分片,同时启动一个 mapper 去读取数据,这样有多少个 block 就有多少个分片,就有多少个 mapper ,这些 mapper 并行读取数据,效率大大提升。上述涉及到几个小概念,接下来分别进行详述。

2.4.1 DEFLATE、DefaultCodec、zlib、gzip 都是什么鬼?

一句话总结: zlib、gzip 在大数据语境中都是一种压缩格式,他们使用相同的压缩算法:DEFLATE,DefaultCodec 是 zlib 使用的编解码器,Gzip 使用的编解码器是 GzipCodec

2.4.2 分片(split)数量如何确定?

我们知道,Hadoop 在任务切分时,是按照文件的粒度进行的。即一个文件一个文件进行切分。而每一个文件切分成几块,取决于 splitSize 的大小。比如两个文件,第一个文件 300M,第二个文件150M。分片大小是128M,那么对于第一个文件将会切分成3片(128M,128M,44M),第二个文件会切分成2片(128M,22M)。共计5片。所以分片数量除了由文件数决定,另一个决定因素就是 splitSize 即分片大小。

splitSize 如何计算?

几个前提:

  1. input format = CombineHiveInputFormat(hive在很早的版本已经将input format默认设置为该格式,而早先的 HiveInputFormat 已经很少使用。虽然 TEZ 默认使用 HiveInputFormat,但如果使用这种输入格式配合 tez.grouping.min-size, tez.grouping.max-size,结果不理想,感兴趣的可以自己试试,欢迎交流)
  2. 关闭输出聚合文件(避免 log 中 mapper 数量显示异常(比如 mapper 数量显示为0,原因未知)。这样可以直接通过最终生成文件数确定 mapper 数量)
  3. 精准控制 splitSize/Mapper 数是很难的,因为数据本地性的存在,mapper 一般运行在数据所在的 datanode,所以通过参数控制 mapper 数量增多或减少的趋势即可。后续实验中 splitSize 值均为估算。

影响参数:

mapreduce.input.fileinputformat.split.minsize
mapreduce.input.fileinputformat.split.maxsize
mapreduce.input.fileinputformat.split.minsize.per.rack
mapreduce.input.fileinputformat.split.minsize.per.node

  • 输入格式不支持分片:mapper 数量 <= 文件数量
  • 输入格式支持分片 :mapper 数量无限制

接下来进行实际验证:

MR 执行引擎配置:

# 使用mr作为执行引擎
set hive.execution.engine=mr;

# 配置输入格式
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;

# 关闭输出聚合
set hive.merge.mapfiles=false;
set hive.merge.mapredfiles=false;

TEZ 执行引擎配置:

# 使用 tez 作为执行引擎
set hive.execution.engine=tez;

# 配置输入格式,这步要注意,MR引擎默认即是 CombineHiveInputFomat。TEZ需要手动配置
set hive.tez.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;

# 关闭输出聚合
set hive.merge.tezfiles=false;

输入格式不支持分片( 不区分 MR、TEZ ):

环境准备:
输入文件(共计30个,864M):
29.9 M  /tmp/yutianci/compress_bench/text_snappy/000000_0.snappy
.
.
.
28.7 M  /tmp/yutianci/compress_bench/text_snappy/000028_0.snappy
4.6 M   /tmp/yutianci/compress_bench/text_snappy/000029_0.snappy

默认配置:
set mapreduce.input.fileinputformat.split.minsize=120000000;
set mapreduce.input.fileinputformat.split.maxsize=240000000;
set mapreduce.input.fileinputformat.split.minsize.per.rack=120000000;
set mapreduce.input.fileinputformat.split.minsize.per.node=120000000;

测试语句:
DROP TABLE split_test;
CREATE TABLE split_test
LOCATION "/tmp/yutianci/compress_bench/split_test" as
select * from text_snappy;
测试结果:

默认:

mapper: 5
splitSize: 172M

验证 minsize.per.node 作用(此处同输入格式支持分片的情况,下略):

set mapreduce.input.fileinputformat.split.minsize=100000000;
set mapreduce.input.fileinputformat.split.maxsize=100000000;

java.io.IOException: Minimum split size pernode 120000000 cannot be larger than maximum split size 100000000

验证 minsize.per.rack 作用(此处同输入格式支持分片的情况,下略):

set mapreduce.input.fileinputformat.split.minsize=100000000;
set mapreduce.input.fileinputformat.split.maxsize=100000000;
set mapreduce.input.fileinputformat.split.minsize.per.node=100000000;

java.io.IOException: Minimum split size per rack 120000000 cannot be larger than maximum split size 100000000

通过正确配置参数增加 splitSize ,减少 mapper :
set mapreduce.input.fileinputformat.split.minsize=500000000;
set mapreduce.input.fileinputformat.split.maxsize=500000000;
set mapreduce.input.fileinputformat.split.minsize.per.rack=500000000;
set mapreduce.input.fileinputformat.split.minsize.per.node=500000000;

mapper: 2
splitSize: 432M

通过正确配置参数减少 splitSize,增加 mapper:

set mapreduce.input.fileinputformat.split.minsize=100000000;
set mapreduce.input.fileinputformat.split.maxsize=100000000;
set mapreduce.input.fileinputformat.split.minsize.per.node=100000000;
set mapreduce.input.fileinputformat.split.minsize.per.rack=100000000;

mapper: 8
splitSize: 108M

通过正确配置参数进一步减少 splitSize,增加 mapper 到极限值,验证输入格式不支持分片时,mapper数量最多是文件个数

set mapreduce.input.fileinputformat.split.minsize=10000000;
set mapreduce.input.fileinputformat.split.maxsize=10000000;
set mapreduce.input.fileinputformat.split.minsize.per.node=10000000;
set mapreduce.input.fileinputformat.split.minsize.per.rack=10000000;

mapper: 30
splitSize: 28M

输入格式支持分片( 不区分 MR、TEZ ):

环境准备:
输入文件情况(共计30个,455M):
15.7 M  /tmp/yutianci/compress_bench/text_bzip2/000000_0.bz2
15.7 M  /tmp/yutianci/compress_bench/text_bzip2/000001_0.bz2
.
.
.
2.4 M   /tmp/yutianci/compress_bench/text_bzip2/000029_0.bz2

默认配置:
set mapreduce.input.fileinputformat.split.minsize=120000000;
set mapreduce.input.fileinputformat.split.maxsize=120000000;
set mapreduce.input.fileinputformat.split.minsize.per.rack=120000000;
set mapreduce.input.fileinputformat.split.minsize.per.node=120000000;

测试语句:
DROP TABLE split_test;
CREATE TABLE split_test
LOCATION "/tmp/yutianci/compress_bench/split_test" as
select * from text_bzip2;

default:

mapper: 4
splitSize: 113M

通过正确配置参数增加 splitSize,减少 mapper:

set mapreduce.input.fileinputformat.split.minsize=500000000;
set mapreduce.input.fileinputformat.split.maxsize=500000000;
set mapreduce.input.fileinputformat.split.minsize.per.rack=500000000;
set mapreduce.input.fileinputformat.split.minsize.per.node=500000000;

mapper: 1
splitSize: 455M

通过正确配置参数减少 splitSize,增加 mapper,验证输入格式支持分片时,mapper 数量不会被文件数限制:

set mapreduce.input.fileinputformat.split.minsize=5000000;
set mapreduce.input.fileinputformat.split.maxsize=5000000;
set mapreduce.input.fileinputformat.split.minsize.per.node=5000000;
set mapreduce.input.fileinputformat.split.minsize.per.rack=5000000;

mapper: 88
splitSize: 5.1M

2.4.3 如何验证一种压缩格式是否支持分片?

经过了 2.4.2 中的一系列实验,验证了一个结论:当一个输入格式支持分片时,mapper 数量是无限制的,反之 mapper 数量小于等于文件的数量。所以我们可以通过设置参数来试图调小分片大小来增加 mapper 数量看其上限是否等于文件数量即可。假如输入的文件个数只有一个,那么当 mapper 数量大于1的时候,说明该输入格式是支持分片的。

3. Deep

3.1 如何选择压缩格式

3.1.1 在自己的数据集上进行测试

#!/bin/bash

#使用方法: ./test_compress.sh uxip.dwd_app_action_detail 20200701 com.meizu.flyme.gamecenter


# init
hadoop fs -rm -R /tmp/yutianci/compress_bench/
hadoop fs -mkdir /tmp/yutianci/compress_bench/
hive -e 'drop database testcompress cascade;'
hive -e 'create database testcompress;'



# no compress
hive -e ' use testcompress;
set hivevar:tablename='$1';
set hivevar:stat_date='$2';
set hivevar:pkg_name='$3';
set hive.exec.compress.output=false;
set orc.compress=NONE;
set parquet.compression=UNCOMPRESSED;

CREATE TABLE text_none
ROW FORMAT DELIMITED FIELDS TERMINATED BY ","
LINES TERMINATED BY "\n"
STORED AS TEXTFILE
LOCATION "/tmp/yutianci/compress_bench/text_none"
as select * from ${tablename} where stat_date=${stat_date} and pkg_name="${pkg_name}";

CREATE TABLE orc_none
STORED AS ORC
LOCATION "/tmp/yutianci/compress_bench/orc_none" as
select * from ${tablename} where stat_date=${stat_date} and pkg_name="${pkg_name}";

CREATE TABLE parquet_none
STORED AS PARQUET
LOCATION "/tmp/yutianci/compress_bench/parquet_none" as
select * from ${tablename} where stat_date=${stat_date} and pkg_name="${pkg_name}";'



# zlib
hive -e ' use testcompress;
set hivevar:tablename='$1';
set hivevar:stat_date='$2';
set hivevar:pkg_name='$3';
set hive.exec.compress.output=true;
set orc.compress=ZLIB;

CREATE TABLE orc_zlib
STORED AS ORC
LOCATION "/tmp/yutianci/compress_bench/orc_zlib" as
select * from ${tablename} where stat_date=${stat_date} and pkg_name="${pkg_name}";'



# gzip
hive -e ' use testcompress;
set hivevar:tablename='$1';
set hivevar:stat_date='$2';
set hivevar:pkg_name='$3';
set hive.exec.compress.output=true;
set mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.GzipCodec;
set parquet.compression=GZIP;

CREATE TABLE parquet_gzip
STORED AS PARQUET
LOCATION "/tmp/yutianci/compress_bench/parquet_gzip" as
select * from ${tablename} where stat_date=${stat_date} and pkg_name="${pkg_name}";


CREATE TABLE text_gzip
STORED AS TEXTFILE
LOCATION "/tmp/yutianci/compress_bench/text_gzip" as
select * from ${tablename} where stat_date=${stat_date} and pkg_name="${pkg_name}";'



# snappy
hive -e ' use testcompress;
set hivevar:tablename='$1';
set hivevar:stat_date='$2';
set hivevar:pkg_name='$3';
set hive.exec.compress.output=true;
set mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.SnappyCodec;
set parquet.compression=SNAPPY;
set orc.compress=SNAPPY;

CREATE TABLE orc_snappy
STORED AS ORC
LOCATION "/tmp/yutianci/compress_bench/orc_snappy" as
select * from ${tablename} where stat_date=${stat_date} and pkg_name="${pkg_name}";


CREATE TABLE parquet_snappy
STORED AS PARQUET
LOCATION "/tmp/yutianci/compress_bench/parquet_snappy" as
select * from ${tablename} where stat_date=${stat_date} and pkg_name="${pkg_name}";


CREATE TABLE text_snappy
STORED AS TEXTFILE
LOCATION "/tmp/yutianci/compress_bench/text_snappy" as
select * from ${tablename} where stat_date=${stat_date} and pkg_name="${pkg_name}";'



# lzo
hive -e ' use testcompress;
set hivevar:tablename='$1';
set hivevar:stat_date='$2';
set hivevar:pkg_name='$3';
set hive.exec.compress.output=true;
set mapreduce.output.fileoutputformat.compress.codec=com.hadoop.compression.lzo.LzopCodec;
set parquet.compression=LZO;

CREATE TABLE parquet_lzo
STORED AS PARQUET
LOCATION "/tmp/yutianci/compress_bench/parquet_lzo" as
select * from ${tablename} where stat_date=${stat_date} and pkg_name="${pkg_name}";


CREATE TABLE text_lzo
STORED AS TEXTFILE
LOCATION "/tmp/yutianci/compress_bench/text_lzo" as
select * from ${tablename} where stat_date=${stat_date} and pkg_name="${pkg_name}";'



# lz4
hive -e ' use testcompress;
set hivevar:tablename='$1';
set hivevar:stat_date='$2';
set hivevar:pkg_name='$3';
set hive.exec.compress.output=true;
set mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.Lz4Codec;


CREATE TABLE text_lz4
STORED AS TEXTFILE
LOCATION "/tmp/yutianci/compress_bench/text_lz4" as
select * from ${tablename} where stat_date=${stat_date} and pkg_name="${pkg_name}";'

# bzip2
hive -e ' use testcompress;
set hivevar:tablename='$1';
set hivevar:stat_date='$2';
set hivevar:pkg_name='$3';
set hive.exec.compress.output=true;
set mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.BZip2Codec;


CREATE TABLE text_bzip2
STORED AS TEXTFILE
LOCATION "/tmp/yutianci/compress_bench/text_bzip2" as
select * from ${tablename} where stat_date=${stat_date} and pkg_name="${pkg_name}";'

hadoop fs -du -h /tmp/yutianci/compress_bench

大家可以根据自己数据集和想测试的压缩和存储格式自行修改脚本。通过以上脚本跑出来的结果如下:

796.2 M  /tmp/yutianci/compress_bench/orc_none
647.5 M  /tmp/yutianci/compress_bench/orc_snappy
430.1 M  /tmp/yutianci/compress_bench/orc_zlib
419.5 M  /tmp/yutianci/compress_bench/parquet_gzip
651.9 M  /tmp/yutianci/compress_bench/parquet_lzo
1.3 G    /tmp/yutianci/compress_bench/parquet_none
681.1 M  /tmp/yutianci/compress_bench/parquet_snappy
454.8 M  /tmp/yutianci/compress_bench/text_bzip2
451.7 M  /tmp/yutianci/compress_bench/text_gzip
729.1 M  /tmp/yutianci/compress_bench/text_lz4
799.1 M  /tmp/yutianci/compress_bench/text_lzo
4.0 G    /tmp/yutianci/compress_bench/text_none

3.1.2 根据需求选择适合当前数据集的压缩

由 2.1 中评价压缩的三项指标可知,压缩率、压缩/解压速度、是否支持分片是衡量压缩最重要的三项指标。3.1.1小节中只对压缩率进行了测试。压缩/解压速度可以通过跑一些查询语句进一步测试。这里就不展开测试了。业界中常用的存储格式一般是 parquet, orc,所以上面测试除了纯文本只测试了这两种存储格式。

3.2 LzoCodec 和 LzopCodec 什么区别?

我们可以通过hive> set io.compression.codecs;来查看当前Hadoop集群支持的压缩,在公司的集群中查询得到的结果是:

io.compression.codecs=org.apache.hadoop.io.compress.GzipCodec,
org.apache.hadoop.io.compress.DefaultCodec,
com.hadoop.compression.lzo.LzoCodec,
com.hadoop.compression.lzo.LzopCodec,
org.apache.hadoop.io.compress.BZip2Codec,
org.apache.hadoop.io.compress.SnappyCodec,
org.apache.hadoop.io.compress.Lz4Codec

可以看到 lzo 有两种编解码器: LzoCodec 和 LzopCodec。他们之间有什么区别呢?

  1. LzoCodec比LzopCodec更快, LzopCodec为了兼容LZOP程序添加了如 bytes signature, header等信息
  2. 如果使用 LzoCodec作为Reduce输出,则输出文件扩展名为".lzo_deflate",它无法被lzop读取;
  3. 如果使用LzopCodec作为Reduce输出,则扩展名为".lzo",它可以被lzop读取 生成lzo index job的"DistributedLzoIndexer"无法为 LzoCodec即 "lzo_deflate"扩展名的文件创建index
  4. "lzo_deflate"文件无法作为MapReduce输入,".LZO"文件则可以。
  • 综上所述得出最佳实践:map输出的中间数据使用 LzoCodec,reduce输出使用 LzopCodec

3.3 snappy 到底是否支持分片?

如果你阅读过关于 Hadoop 压缩的文章,应该可以看到,绝大多数文章中对于 snappy 是否支持分片都是直接给出的否定的答案。CDH 的文档中也指出来 snappy 是不支持分片的。

For MapReduce and Spark, if you need your compressed data to be splittable, BZip2 and LZO formats can be split. Snappy and GZip blocks are not splittable, but files with Snappy blocks inside a container file format such as SequenceFile or Avro can be split. Snappy is intended to be used with a container format, like SequenceFiles or Avro data files, rather than being used directly on plain text, for example, since the latter is not splittable and cannot be processed in parallel. Splittability is not relevant to HBase data.

看文中加粗片段,虽然 snappy 本身是不支持分片的,但是如果 snappy 存储在一些特定的存储格式比如 SequenceFile 或者 Avro 中,那么是可以支持分片的。也就是说 snappy 是否支持分片是分情况讨论的。不能说使用了 snappy 压缩就一定不支持分片。前面提到了,业界中常用的存储格式一般是 parquet 或者 orc,而上面 CDH 的文章中恰恰没有提到 parquet 和 orc 是否支持,接下来以 parquet 为例,进行测试。测试内容即为 parquet + snappy 组合,是否支持分片。
首先准备数据,因为之前做压缩率测试,已经有了 parquet + snappy 文件了,这里直接拿来用。

环境准备:
输入文件情况(共计3个,681M):
260.4 M  /tmp/yutianci/compress_bench/parquet_snappy/000000_0
253.6 M  /tmp/yutianci/compress_bench/parquet_snappy/000001_0
167.1 M  /tmp/yutianci/compress_bench/parquet_snappy/000002_0

参数配置:
set hive.execution.engine=tez;
set hive.tez.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
set hive.merge.tezfiles=false;
set mapreduce.input.fileinputformat.split.minsize=120000000;
set mapreduce.input.fileinputformat.split.maxsize=120000000;
set mapreduce.input.fileinputformat.split.minsize.per.rack=120000000;
set mapreduce.input.fileinputformat.split.minsize.per.node=120000000;

测试语句:
DROP TABLE split_test;
CREATE TABLE split_test
LOCATION "/tmp/yutianci/compress_bench/split_test" as
select * from parquet_snappy;

测试结果:
Mapper: 6

一共3个输入文件,启了6个mapper,说明输入文件是可以分片的。即 parquet + snappy 的组合是支持分片的。在《Hadoop The Definitive Guide》中也对 parquet 是否支持分片有说明:

The consequence of storing the metadata in the footer is that reading a Parquet file requires an initial seek to the end of the file (minus 8 bytes) to read the footer metadata length, then a second seek backward by that length to read the footer metadata. Unlike sequence files and Avro datafiles, where the metadata is stored in the header and sync markers are used to separate blocks, Parquet files don’t need sync markers since the block boundaries are stored in the footer metadata. (This is possible because the metadata is written after all the blocks have been written, so the writer can retain the block boundary positions in memory until the file is closed.) Therefore, Parquet files are splittable, since the blocks can be located after reading the footer and can then be processed in parallel (by MapReduce, for example).

3.4 hadoop,hive,table关于压缩的配置参数如何作用?

以 mapreduce.output.fileoutputformat.compress.codec 为例,这个参数可以在三个地方配置:

  1. Hadoop 中,比如$HADOOP_HOME/etc/hadoop/mapred-site.xml
  2. hive 中,比如 hive 命令行中直接通过 set 命令设置
  3. 表级别,比如存储格式中的压缩,以 parquet 为例,可以通过
    hive> set parquet.compression=SNAPPY; 来设置 parquet 使用 SNAPPY 压缩。

那么当三者都设置时,以哪个为准呢?按照经验来看,一定是粒度小的优先级大于粒度大的优先级。经过测试也验证了这种猜测。即:表级别 > hive > hadoop

3.5 存储格式和压缩格式的关系?

初学者往往容易混淆存储格式和压缩格式之间的关系,其实二者是完全独立的。如果完整的阅读了该篇文章,应该已经消除了这一块理解对误区。这里总结一下:比如 parquet, orc,他们都是常见的存储格式。是否使用压缩,使用何种压缩都是可以设置的。而 zlib、gzip、lzo、lz4、snappy 等等这些都是常见的压缩格式,他们既可以依附于某些存储格式,比如之前提到的 parquet + snappy,orc + zlib 等等。也可以脱离特定的 存储格式,比如纯文本文件进行压缩,text + parquet, text + bzip2 等等。

4. Ref

  1. Hadoop 压缩形式和 Hive 存储格式之介绍以及对比分析案例
  2. hadoop 2.4 支持 snappy
  3. Hadoop Compression. Compression rate. Part1
  4. Hadoop Compression. Choosing compression codec. Part2
  5. https://stackoverflow.com/questions/32382352/is-snappy-splittable-or-not-splittable
  6. https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL
  7. parquet支持的压缩格式
  8. orc 支持的压缩方式
  9. https://docs.cloudera.com/documentation/enterprise/5-8-x/topics/cdh_ig_parquet.html
  10. 控制map个数与性能调优参数
  11. CombineHiveInputFormat map数计算
  12. https://knpcode.com/hadoop/hadoop-io/data-compression-hadoop-framework/

你可能感兴趣的:(Hadoop 压缩从理论到实战)