最近在筹备hadoop,测试集群只有普通的6个虚拟机,每个1G内存,100G硬盘。所以在yarn进行资源调度的时候比较纠结,硬盘空间也有限。在执行作业的时候就希望能够尽量对输入数据进行压缩。
成都创新互联-云计算及IDC服务提供商,涵盖公有云、IDC机房租用、成都服务器托管、等保安全、私有云建设等企业级互联网基础服务,服务电话:18980820575
hadoop可以直接处理gz格式的压缩文件,但不会产生split,而是不论多大都直接交给一个Mapper去做,因为gz在算法上不支持split。虽然bzip2支持split,但压缩速度又比较慢,gz可以说是最常用的压缩方式了。
一开始想当然的尝试压缩分卷,结果当然是失败,因为不管分多少个卷,gz还是要以一个整体来进行解压。
因为我只是处理文本数据,而且都是基于文本行,每一行之间不像xml那样会具有什么嵌套关系,所以动手写了一个压缩程序,在对大文件进行压缩的时候,如果产生的压缩文件大于一个设定值,那就再新建一个文件继续压缩。
package util; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.util.zip.GZIPOutputStream; public class CompressUtils { /** * 将文件压缩成GZIP分片 * @param inputFile 输入文件 * @param outputDir 输出目录 * @param outputFileName 输出文件名 * @param splitSize 分片大小 */ public static void compressToSplitsUseGZIP(File inputFile, File outputDir, String outputFileName, int splitSize) throws Exception { String separator = System.getProperty("line.separator"); int split = 0; long limit = splitSize * 1024 * 1024L; File outputSplit = new File(outputDir, outputFileName + split + ".gz"); outputSplit.createNewFile(); BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(inputFile), "UTF-8")); PrintWriter out = new PrintWriter(new GZIPOutputStream(new FileOutputStream(outputSplit)), false); String line = null; long fileLength = outputSplit.length(); long maxInc = 0L; while (true) { line = br.readLine(); if (line == null) { break; } if (fileLength + maxInc > limit) { if (out != null) { out.close(); out = null; outputSplit = new File(outputDir, outputFileName + (++split) + ".gz"); outputSplit.createNewFile(); fileLength = outputSplit.length(); out = new PrintWriter(new GZIPOutputStream( new FileOutputStream(outputSplit)), false); } } for (byte b : line.getBytes()) { out.write(b); } for (byte b : separator.getBytes()) { out.write(b); } out.flush(); long currentLength = outputSplit.length(); long inc = currentLength - fileLength; if (inc >= maxInc) { maxInc = inc; } fileLength = currentLength; } br.close(); try { out.close(); } catch (Exception e) { } } public static void main(String[] args) throws Exception { File inputFile = new File(args[0]); File outputDir = new File(args[1]); String outputFileName = args[2]; int splitSize = Integer.parseInt(args[3]); compressToSplitsUseGZIP(inputFile, outputDir, outputFileName, splitSize); } }
命令行参数:D:\temp\test.txt D:\temp test 64
这样产生的压缩文件每一个都会小于64MB,最多相差不到100k。考虑的因素比较少,这里只是把大致的算法写了一下,倒是满足需求了。