Hadoop中的压缩(1) 概述与实例

1 概述

文件压缩主要有两个好处,一是减少了存储文件所占空间,另一个就是为数据传输提速。在hadoop大数据的背景下这两点尤为重要。hadoop里支持很多种压缩格式:


DEFLATE是同时使用了LZ77算法与哈夫曼编码(Huffman Coding)的一个无损数据压缩算法,源代码可以在zlib库中找到。gzip是以DEFLATE算法为基础扩展出来的一种算法。

压缩算法

原始文件大小

压缩后的文件大小

压缩速度

解压缩速度

gzip  

8.3GB  

1.8GB

17.5MB/s

58MB/s

bzip2

8.3GB

1.1GB

2.4MB/s

9.5MB/s

LZO-bset

8.3GB

2GB

4MB/s

60.6MB/s

LZO

8.3GB

2.9GB

49.3MB/S

74.6MB/s

 

 

 





所有的压缩算法都是空间和时间的转换,更快压缩时间还是更小的压缩比,可以通过参数来指定,-1意味着速度,-9意味着空间。拿gzip做个例子,下面就意味着更快速的压缩:gzip -1 file


gzip在时间和空间上的取舍比较折中,bzip2压缩比gzip更有效,但是速度更慢。bzip2的解压速度比它的压缩速度要快。但是和其他压缩格式比又是最慢的,但是压缩效果明显是最好的。snappy和lz4的解压速度比lzo好很多。splittable表示压缩格式是否可以被分割,也就是说是否支持随即读。压缩数据是否能被mapreduce使用,压缩数据是否能被分割就很关键了。


举例一个未压缩的文件有1GB大小,hdfs默认的block大小是64MB,那么这个文件就会被分为16个block作为mapreduce的输入,每一个单独使用一个map任务。若该文件是已经使用gzip压缩的呢,若分成16个块,每个块做成一个输入,显然是不合适的,因为gzip压缩流的随即读是不可能的。实际上,当mapreduce处理压缩格式的文件的时候它会认识到这是一个gzip的压缩文件,而gzip又不支持随即读,它就会把16个块分给一个map去处理,这里就会有很多非本地处理的map任务,整个过程耗费的时间就会相当长。lzo压缩格式也会是同样的问题,但是通过使用hadoop lzo库的索引工具以后,lzo就可以支持splittable。bzip2也是支持splittable的。


详见hadoop-2.5.2-src源码中的FileInputFormat类中的getSplits方法

        if (isSplitable(fs, path)) {
          long blockSize = file.getBlockSize();
          long splitSize = computeSplitSize(goalSize, minSize, blockSize);

          long bytesRemaining = length;
          while (((double) bytesRemaining)/splitSize > SPLIT_SLOP) {
            String[] splitHosts = getSplitHosts(blkLocations,
                length-bytesRemaining, splitSize, clusterMap);
            splits.add(makeSplit(path, length-bytesRemaining, splitSize,
                splitHosts));
            bytesRemaining -= splitSize;
          }

          if (bytesRemaining != 0) {
            String[] splitHosts = getSplitHosts(blkLocations, length
                - bytesRemaining, bytesRemaining, clusterMap);
            splits.add(makeSplit(path, length - bytesRemaining, bytesRemaining,
                splitHosts));
          }
        } else {
          String[] splitHosts = getSplitHosts(blkLocations,0,length,clusterMap);
          splits.add(makeSplit(path, 0, length, splitHosts));
        }

那么如何选择压缩格式呢?这取决于文件的大小,你使用的压缩工具,下面是几条选择建议,效率由高到低排序:
1用一些包含了压缩并且支持splittable的文件格式,比如Sequence File,RCFile或者Avro文件,这些文件格式我们之后都会讲到。若为了快速压缩可以使用lzo,lz4或者snappy压缩格式。
2 使用提供splittable的压缩格式,比如,bzip2和索引后可以支持splittable的lzo。
3 提前把文件分成几个块,每个块单独压缩,这样就无需考虑splittable的问题了
4 不要压缩文件。以不支持splittable的压缩格式存储一个很大的数据文件是不合适的,非本地处理效率会非常之低。


2 代码

codec其实就是coder和decoder两个单词的词头组成的缩略词。CompressionCodec定义了压缩和解压接口,所以又叫编码解码器。为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器,如下表所示

压缩格式

对应的编码/解码器

DEFLATE

org.apache.hadoop.io.compress.DefaultCodec

gzip

org.apache.hadoop.io.compress.GzipCodec

bzip

org.apache.hadoop.io.compress.Bzip2Codec

Snappy

org.apache.hadoop.io.compress.SnappyCodec

public class TestCompress {
	public static void main(String[] args) throws IOException,
			InterruptedException, ClassNotFoundException {
		// 将a.txt压缩为a.txt.bz2
		compress("E://a.txt", "BZip2Codec");
		// 将a.txt.bz2解压为a.txt.bz2.decoded
		decompres("E://a.txt.bz2");
		System.out.println("down");
	}

	/**
	 * 压缩方法
	 * @param filename 待压缩的文件路径
	 * @param method 压缩方法名
	 */
	public static void compress(String filePath, String method)
			throws ClassNotFoundException, IOException {

		// 需要被压缩的文件
		File fileIn = new File(filePath);
		InputStream in = new FileInputStream(fileIn);

		// 通过名称反射得到编码解码器
		Configuration conf = new Configuration();
		Class<?> codecClass = Class.forName("org.apache.hadoop.io.compress."
				+ method);
		CompressionCodec codec = (CompressionCodec) ReflectionUtils
				.newInstance(codecClass, conf);
		// 获取文件扩展名并创建结果文件名
		File fileOut = new File(filePath + codec.getDefaultExtension());
		OutputStream out = new FileOutputStream(fileOut);
		// 输出到结果文件,缓冲区设为5MB
		CompressionOutputStream cout = codec.createOutputStream(out);
		IOUtils.copyBytes(in, cout, 1024 * 1024 * 5, false);
		System.out.println("compress success");
		in.close();
		cout.close();
	}

	/**
	 * 解压方法
	 * @param filename 待解压的文件
	 */
	public static void decompres(String filePath) throws FileNotFoundException,
			IOException {
		// 根据文件后缀获取解码器
		Configuration conf = new Configuration();
		CompressionCodecFactory factory = new CompressionCodecFactory(conf);
		CompressionCodec codec = factory.getCodec(new Path(filePath));
		if (null == codec) {
			System.out.println("Cannot find codec for file " + filePath);
			return;
		}
		// 获取输入流
		InputStream cin = codec
				.createInputStream(new FileInputStream(filePath));
		// 输出文件
		File fout = new File(filePath + ".decoded");
		OutputStream out = new FileOutputStream(fout);
		IOUtils.copyBytes(cin, out, 1024 * 1024 * 5, false);
		System.out.println("decompres success");
		cin.close();
		out.close();
	}
}

原贴地址:http://blog.csdn.net/lastsweetop/article/details/9162031

优秀的个人博客,低调大师

微信关注我们

原文链接:https://yq.aliyun.com/articles/67313

转载内容版权归作者及来源网站所有!

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

相关文章

发表评论

资源下载

更多资源
Mario,低调大师唯一一个Java游戏作品

Mario,低调大师唯一一个Java游戏作品

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Oracle Database,又名Oracle RDBMS

Oracle Database,又名Oracle RDBMS

Oracle Database,又名Oracle RDBMS,或简称Oracle。是甲骨文公司的一款关系数据库管理系统。它是在数据库领域一直处于领先地位的产品。可以说Oracle数据库系统是目前世界上流行的关系数据库管理系统,系统可移植性好、使用方便、功能强,适用于各类大、中、小、微机环境。它是一种高效率、可靠性好的、适应高吞吐量的数据库方案。

Java Development Kit(Java开发工具)

Java Development Kit(Java开发工具)

JDK是 Java 语言的软件开发工具包,主要用于移动设备、嵌入式设备上的java应用程序。JDK是整个java开发的核心,它包含了JAVA的运行环境(JVM+Java系统类库)和JAVA工具。

Sublime Text 一个代码编辑器

Sublime Text 一个代码编辑器

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。