【MapReduce】四、Hadoop数据压缩

it2024-11-15  2

文章目录

一、概述二、MR支持的压缩编码三、压缩方式选择四、压缩位置选择五、压缩参数配置六、压缩实操案例

一、概述

压缩技术能够有效减少底层存储系统(HDFS)读写字节数。压缩提高了网络带宽和磁盘空间的效率。在运行MR程序时,IO操作、网络数据传输、Shuffle和Merge要花大量的时间,尤其是数据规模很大和工作负载密集的情况下,因此,使用数据压缩显得非常重要。鉴于磁盘I/o和网络带宽是Hadoop的宝贵资源,数据压缩对于节省资源、最小化磁盘I/O和网络传输非常有帮助。可以在任意MapReduce阶段启用压缩。不过,尽管压缩与解压操作的CPU开销不高,其性能的提升和资源的节省并非没有代价。压缩是提高Hadoop运行效率的一种优化策略。通过对Mapper、Reducer运行过程的数据进行压缩,以减少磁盘Io,提高MR程序运行速度。注意:采用压缩技术减少了磁盘Io,但同时增加了CPU运算负担。所以,压缩特性运用得当能提高性能,但运用不当也可能降低性能。压缩基本原则: (1)运算密集型的job,少用压缩 (2)IO密集型的job,多用压缩

二、MR支持的压缩编码

压缩编码 为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 压缩性能的比较

三、压缩方式选择

Gzip压缩 1.1 优点:压缩率比较高,而且压缩/解压速度也比较快;Hadoop本身支持,在应用中处理Gzip格式的文件就和直接处理文本一样;大部分Linux系统都自带Gzip命令,使用方便。 1.2 缺点:不支持Split。 1.3 应用场景:当每个文件压缩之后在130M以内的(1个块大小内),都可以考虑用Gzip压缩格式。例如说一天或者一个小时的日志压缩成一个Gzip文件。

Bzip2压缩 2.1 优点:支持split;具有很高的压缩率,比Gzip压缩率都高;Hadoop本身自带,使用方便。 2.2 缺点:压缩/解压速度慢。 2.3 应用场景:适合对速度要求不高,但需要较高的压缩率的时候;或者输出之后的数据比较大,处理之后的数据需要压缩存档减少磁盘空间并且以后数据用得比较少的情况;或者对单个很大的文本文件想压缩减少存储空间,同时又需要支持split,而且兼容之前的应用程序的情况。

Lzo压缩 3.1 优点:压缩/解压速度也比较快,合理的压缩率;支持Split,是Hadoop中最流行的压缩格式;可以在Linux系统下安装lzop命令,使用方便。 3.2 缺点∶压缩率比Gzip要低一些; Hadoop本身不支持,需要安装;在应用中对Lzo格式的文件需要做一些特殊处理(为了支持Split需要建索引,还需要指定InputFormat为Lzo格式)。 3.3 应用场景:一个很大的文本文件,压缩之后还大于200M以上的可以考虑,而旦单个文件越大,Lzo优点越越明显。

Snappy压缩 4.1 优点:高速压缩速度和合理的压缩率。 4.2 缺点:不支持Split;压缩率比Gzip要低;Hadoop本身不支持,需要安装。 4.3 应用场景:当MapRedce作业的Map输出的数据比较大的时候,作为Map到Reduce的中间数据的压缩格式;或者作为一个MapReduce作业的输出和另外一个MapReduce作业的输入。

四、压缩位置选择

压缩可以在MapReduce作用的任意阶段启用:

五、压缩参数配置

要在Hadoop中启用压缩,可以配置如下参数:

六、压缩实操案例

数据流的压缩和解压缩 CompressionCodec有两个方法可以用于轻松地压缩或解压缩数据。 要想对正在被写入一个输出流的数据进行压缩,我们可以使用createOutputStream(OutputStreamout)方法创建一个CompressionOutputStream,将其以压缩格式写入底层的流。 相反,要想对从输入流读取而来的数据进行解压缩,则调用createInputStream(InputStreamin)函数,从而获得一个CompressionInputStream,从而从底层的流读取未压缩的数据。 测试一下如下压缩方式: package com.until.mapreduce.compress; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.IOUtils; import org.apache.hadoop.io.compress.CompressionCodec; import org.apache.hadoop.io.compress.CompressionCodecFactory; import org.apache.hadoop.io.compress.CompressionInputStream; import org.apache.hadoop.io.compress.CompressionOutputStream; import org.apache.hadoop.util.ReflectionUtils; public class TestCompress { public static void main(String[] args) throws Exception { compress("e:/hello.txt","org.apache.hadoop.io.compress.BZip2Codec"); // decompress("e:/hello.txt.bz2"); } // 1、压缩 private static void compress(String filename, String method) throws Exception { // (1)获取输入流 FileInputStream fis = new FileInputStream(new File(filename)); Class codecClass = Class.forName(method); CompressionCodec codec = (CompressionCodec) ReflectionUtils.newInstance(codecClass, new Configuration()); // (2)获取输出流 FileOutputStream fos = new FileOutputStream(new File(filename + codec.getDefaultExtension())); CompressionOutputStream cos = codec.createOutputStream(fos); // (3)流的对拷 IOUtils.copyBytes(fis, cos, 1024*1024*5, false); // (4)关闭资源 cos.close(); fos.close(); fis.close(); } // 2、解压缩 private static void decompress(String filename) throws FileNotFoundException, IOException { // (0)校验是否能解压缩 CompressionCodecFactory factory = new CompressionCodecFactory(new Configuration()); CompressionCodec codec = factory.getCodec(new Path(filename)); if (codec == null) { System.out.println("cannot find codec for file " + filename); return; } // (1)获取输入流 CompressionInputStream cis = codec.createInputStream(new FileInputStream(new File(filename))); // (2)获取输出流 FileOutputStream fos = new FileOutputStream(new File(filename + ".decoded")); // (3)流的对拷 IOUtils.copyBytes(cis, fos, 1024*1024*5, false); // (4)关闭资源 cis.close(); fos.close(); } } Map输出端采用压缩 即使你的MapReduce的输入输出文件都是未压缩的文件,你仍然可以对Map任务的中间结果输出做压缩,因为它要写在硬盘并且通过网络传输到Reduce节点,对其压缩可以提高很多性能,这些工作只要设置两个属性即可,我们来看下代码怎么设置。 2.1 提供的Hadoop源码支持的压缩格式有:BZip2Codec 、DefaultCodec 1)WordcountDriver package com.until.mapreduce; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.io.compress.BZip2Codec; import org.apache.hadoop.io.compress.CompressionCodec; import org.apache.hadoop.mapreduce.Job; import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; import java.io.IOException; public class WordcountDriver { // static { // try { // System.load("C:/mine/software/hadoop-2.7.2/bin/hadoop.dll"); // } catch (UnsatisfiedLinkError e) { // System.err.println("Native code library failed to load.\n" + e); // System.exit(1); // } // } public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException { //1获取配置信息以及封装任务 Configuration configuration = new Configuration(); // 开启map端输出压缩 configuration.setBoolean("mapreduce.map.output.compress", true); // 设置map端输出压缩方式 configuration.setClass("mapreduce.map.output.compress.codec", BZip2Codec.class, CompressionCodec.class); Job job = Job.getInstance(configuration); //2设置jar加载路径 job.setJarByClass(WordcountDriver.class); //3设置map和reduce类 job.setMapperClass(WordcountMapper.class); job.setReducerClass(WordcountReducer.class); //4 设置map输出 job.setMapOutputKeyClass(Text.class); job.setMapOutputValueClass(IntWritable.class); //5设置最终输出kv类型 job.setOutputKeyClass(Text.class); job.setOutputValueClass(IntWritable.class); //6设置输入和输出路径 FileInputFormat.setInputPaths(job, new Path(args[0])); FileOutputFormat.setOutputPath(job, new Path(args[1])); //7提交 boolean result = job.waitForCompletion(true); System.exit((result ? 0 : 1)); } }

2)WordcountMapper

package com.until.mapreduce; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Mapper; import java.io.IOException; import java.nio.MappedByteBuffer; public class WordcountMapper extends Mapper<LongWritable,Text, Text, IntWritable> { Text k = new Text(); IntWritable v = new IntWritable(1); @Override protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { // 1.获取一行 String line = value.toString(); // 2.切割 String[] words = line.split(" "); // 3.输出 for (String word : words) { k.set(word); context.write(k,v); } } }

3)WordcountReducer

package com.until.mapreduce; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Reducer; import org.junit.Test; import java.io.IOException; public class WordcountReducer extends Reducer<Text,IntWritable,Text,IntWritable>{ int sum; IntWritable v = new IntWritable(); @Override protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException { // 1.累加求和 sum = 0; for (IntWritable count : values) { sum += count.get(); } // 2.输出 v.set(sum); context.write(key,v); } } Reduce输出端采用压缩 基于WordCount案例处理(修改上面的例子) 修改WordcountDriver类即可,Mapper和Reducer保持不变: // 设置reduce端输出压缩开启 FileOutputFormat.setCompressOutput(job, true); // 设置压缩的方式 FileOutputFormat.setOutputCompressorClass(job, BZip2Codec.class);
最新回复(0)