1、压缩格式比较(Hadoop压缩配置)
先放图
snappy虽然不可切分,但也是对已生成的文件,可以在mr阶段指定reduce个数控制生成的文件大小
每一个压缩方案都在压缩/解压缩速度和压缩率间进行权衡。BZip2压缩率最高,但是同时需要消耗最多的CPU开销。GZip是压缩率和压缩/解压缩速度上的下一个选择。因此,如果磁盘空间利用率和I/O开销都需要考虑的话,那么这2种压缩方案都是有吸引力的。
LZO和Snappy压缩率相比前面的2种要小但是压缩/解压缩速度要快,特别是解压缩过程。如果相对于磁盘空间和I/O开销,频繁读取数据所需的解压缩速度更重要的话,那么它们将是不错的选择。
2、中间压缩
对中间数据进行压缩可以减少job中map和reduce task间的数据传输量。对于中间数据压缩,选择一个低CPU开销的编/解码器要比选择一个压缩率高的编/解码器要重要得多。属性hive.exec.compress. intermediate的默认值是false,如果要开启中间压缩,就需要将这个属性值修改为默认值为true
<property>
<name>hive.exec.compress.intermediate</name>
<value>true</value>
<description> This controls whether intermediate files produced by Hive between
multiple map-reduce jobs are compressed. The compression codec and other options
are determined from hadoop config variables mapred.output.compress* </description>
</property>
Hadoop压缩默认的编/解码器是DefaultCodec。可以通过修改属性mapred.map.output.compression.codec的值来修改编/解码器。这是一个Hadoop配置项,可以在 H A D O O P H O M E / c o n f / m a p r e d − s i t e . x m l 文件中或 HADOOP_HOME/conf/mapred-site.xml文件中或 HADOOPHOME/conf/mapred−site.xml文件中或HADOOP_HOME/conf/hive-site.xml文件中进行配置。SnappyCodec是一个比较好的中间文件压缩编/解码器,因为其很好地结合了低CPU开销和好的压缩执行效率:
<property>
<name>mapred.map.output.compression.codec</name>
<value>org.apache.hadoop.io.compress.SnappyCodec</value>
<description> This controls whether intermediate files produced by Hive
between multiple map-reduce jobs are compressed. The compression codec
and other options are determined from hadoop config variables
mapred.output.compress* </description>
</property>
3、最终输出结果压缩
当Hive将输出写入到表中时,输出内容同样可以进行压缩。属性hive.exec. compress.output控制着这个功能。用户可能需要保持默认配置文件中的默认值false,这样默认的输出就是非压缩的纯文本文件了。用户可以通过在查询语句或执行脚本中设置这个值为true,来开启输出结果压缩功能:
<property>
<name>hive.exec.compress.output</name>
<value>false</value>
<description> This controls whether the final outputs of a query
(to a local/hdfs file or a Hive table) is compressed. The compression
codec and other options are determined from hadoop config variables
mapred.output.compress* </description>
</property>
对于其他Hadoop 任务,开启最终输出结果压缩功能的属性是mapred.output.compress。
如果属性hive.exec.compress.output的值设置为true,那么这时需要为其指定一个编解码器。对于输出文件,使用GZip进行压缩是个不错的主意,因为其通常可以大幅度降低文件的大小。但是,需要记住的是GZip压缩的文件对于后面的MapReduce job而言是不可分割的。
4、sequence file存储格式
Sequence file提供了3种压缩方式:NONE、RECORD和BLOCK,默认是RECORD级别(也就是记录级别)。不过,通常来说,BLOCK级别(也就是块级别)压缩性能最好而且是可以分割的。和很多其他的压缩属性一样,这个属性也并非是Hive特有的。用户可以在Hadoop的mapred-site.xml文件中进行定义,或者在Hive的hive-site.xml文件中进行定义,需要的时候,还可以在脚本中或查询语句前进行指定:
<property>
<name>mapred.output.compression.type</name>
<value>BLOCK</value>
<description>If the job outputs are to compressed as SequenceFiles,
how should they be compressed? Should be one of NONE, RECORD or BLOCK.
</description>
</property>
5、使用压缩实践
开启一个Hive会话:
hive> SELECT * FROM a;
4 5
3 2
hive> DESCRIBE a;
a int
b int
首先,我们先开启中间数据压缩功能。这将不会影响到最终输出结果。不过从job的计数器信息上看,可以发现这个job中间传送的数据量变小了,因为shuffle sort(混洗排序)数据被压缩了:
hive> set hive.exec.compress.intermediate=true;
hive> CREATE TABLE intermediate_comp_on
> ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
> AS SELECT * FROM a;
Moving data to: file:/user/hive/warehouse/intermediate_comp_on
Table default.intermediate_comp_on stats: [num_partitions: 0, num_files: 1,
num_rows: 2, total_size: 8, raw_data_size: 6]
...
和预期的一样,中间数据压缩没有影响到最终的输出,最终的数据结果仍然是非压缩的:
hive> dfs -ls /user/hive/warehouse/intermediate_comp_on;
Found 1 items
/user/hive/warehouse/intermediate_comp_on/000000_0
hive> dfs -cat /user/hive/warehouse/intermediate_comp_on/000000_0;
4 5
3 2
我们同样可以为中间数据压缩配置其他的编/解码器而不使用默认的编/解码器。下面这个例子,我们选择使用GZip(尽管通常Snappy是更好的选择)。为显示清晰,将下面语句中的第1行分成了2行:
hive> set mapred.map.output.compression.codec
=org.apache.hadoop.io.compress.GZipCodec;
hive> set hive.exec.compress.intermediate=true;
hive> CREATE TABLE intermediate_comp_on_gz
> ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
> AS SELECT * FROM a;
Moving data to: file:/user/hive/warehouse/intermediate_comp_on_gz
Table default.intermediate_comp_on_gz stats:
[num_partitions: 0, num_files: 1, num_rows: 2, total_size: 8, raw_data_size:6]
hive> dfs -cat /user/hive/warehouse/intermediate_comp_on_gz/000000_0;
4 5
3 2
下一步,我们可以开启输出结果压缩:
hive> set hive.exec.compress.output=true;
hive> CREATE TABLE final_comp_on
> ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
> AS SELECT * FROM a;
Moving data to: file:/tmp/hive-edward/hive_2012-01-15_11-11-01_884_.../-ext-10001
Moving data to: file:/user/hive/warehouse/final_comp_on
Table default.final_comp_on stats:
[num_partitions: 0, num_files: 1, num_rows: 2, total_size: 16, raw_data_size:6]
hive> dfs -ls /user/hive/warehouse/final_comp_on;
Found 1 items
/user/hive/warehouse/final_comp_on/000000_0.deflate
输出信息中的表统计信息显示total_size(总大小)是16B,但是raw_data_size(裸数据)是6B,多出的存储空间是被deflate算法消耗了。同时我们可以看到,输出的文件后缀名是.deflate。
不推荐使用cat命令来查看这个压缩文件,因为用户只能看到二进制输出。不过,Hive可以正常地查询这个数据:
hive> dfs -cat /user/hive/warehouse/final_comp_on/000000_0.deflate;
... UGLYBINARYHERE ...
hive> SELECT * FROM final_comp_on;
4 5
3 2
这种无缝的处理压缩文件的能力并非是Hive独有的,实际上,这里是使用了Hadoop的TextInputFormat进行的处理。尽管在这种情况下这个命名有些令人混淆,但是TextInputFormat可以识别文件后缀名为.deflate或.gz的压缩文件,并且可以很轻松地进行处理。Hive无需关心底层的文件是否是压缩的,以及是使用何种压缩方案进行压缩的。
下面我们改变下输出结果压缩所使用的编解码器,然后看下结果(这里语句的第2行为了显示清晰,也分成2行了):
hive> set hive.exec.compress.output=true;
hive> set mapred.output.compression.codec
=org.apache.hadoop.io.compress.GzipCodec;
hive> CREATE TABLE final_comp_on_gz
> ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
> AS SELECT * FROM a;
Moving data to: file:/user/hive/warehouse/final_comp_on_gz
Table default.final_comp_on_gz stats:
[num_partitions: 0, num_files: 1, num_rows: 2, total_size: 28, raw_data_ size:6]
hive> dfs -ls /user/hive/warehouse/final_comp_on_gz;
Found 1 items
/user/hive/warehouse/final_comp_on_gz/000000_0.gz
正如用户可以看到的,输出文件夹下现在包含了零个或多个.gz文件。Hive提供了在Hive shell中执行像zcat这样的本地命令的快速方法。通过!符号,Hive可以执行外部的命令,直到返回结果。
zcat是一个命令行实用程序,用来解压缩,并进行输出显示:
hive> ! /bin/zcat /user/hive/warehouse/final_comp_on_gz/000000_0.gz;
4 5
3 2
hive> SELECT * FROM final_comp_on_gz;
OK
4 5
3 2
Time taken: 0.159 seconds
使用这种输出压缩能够完成那种很小,操作起来很快的文件的二进制压缩。不过,回想一下,输出文件的个数是和处理数据所需要的mapper个数或reducers个数有关的。在最坏的情况下,可能最终结果是文件夹中只产生了一个大的压缩文件,而且是不可分割的。这意味着后续步骤并不能并行地处理这个数据。解决这个问题的答案就是使用sequence file:
hive> set mapred.output.compression.type=BLOCK;
hive> set hive.exec.compress.output=true;
hive> set mapred.output.compression.codec=org.apache.hadoop.io.compress. GzipCodec;
hive> CREATE TABLE final_comp_on_gz_seq
> ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
> STORED AS SEQUENCEFILE
> AS SELECT * FROM a;
Moving data to: file:/user/hive/warehouse/final_comp_on_gz_seq
Table default.final_comp_on_gz_seq stats:
[num_partitions: 0, num_files: 1, num_rows: 2, total_size: 199, raw_data_ size: 6]
hive> dfs -ls /user/hive/warehouse/final_comp_on_gz_seq;
Found 1 items
/user/hive/warehouse/final_comp_on_gz_seq/000000_0
Sequence file是二进制格式的,但是,我们可以很容易地查询文件头。通过查看文件头可以确认结果是否是我们需要的(为方便显示,输出格式进行了调整):
hive> dfs -cat /user/hive/warehouse/final_comp_on_gz_seq/000000_0;
SEQ[]org.apache.hadoop.io.BytesWritable[]org.apache.hadoop.io.BytesWritable[]
org.apache.hadoop.io.compress.GzipCodec[]
因为sequence file中嵌入的元数据信息以及Hive元数据信息,Hive无需任何特别的设置就可以查询这张表。Hadoop同样提供了dfs –text命令来从sequence file文件中去除掉文件头和压缩,然后显示裸数据:
hive> dfs -text /user/hive/warehouse/final_comp_on_gz_seq/000000_0;
4 5
3 2
hive> select * from final_comp_on_gz_seq;
OK
4 5
3 2
最后,我们来同时使用直接数据压缩和最终输出数据压缩,而且使用不同压缩编/解码器的sequence file!这些设置通常应用在生产环境,这些环境中的数据集很大,而这些设置可以提高其性能:
hive> set mapred.map.output.compression.codec
=org.apache.hadoop.io.compress.SnappyCodec;
hive> set hive.exec.compress.intermediate=true;
hive> set mapred.output.compression.type=BLOCK;
hive> set hive.exec.compress.output=true;
hive> set mapred.output.compression.codec
=org.apache.hadoop.io.compress.GzipCodec;
hive> CREATE TABLE final_comp_on_gz_int_compress_snappy_seq
> ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
> STORED AS SEQUENCEFILE AS SELECT * FROM a;