为啥 Hadoop SequenceFile 写入比读取慢得多?

Posted

技术标签:

【中文标题】为啥 Hadoop SequenceFile 写入比读取慢得多?【英文标题】:Why Hadoop SequenceFile writing is much slower than reading?为什么 Hadoop SequenceFile 写入比读取慢得多? 【发布时间】:2012-03-02 09:50:39 【问题描述】:

我正在使用 Java API 将我拥有的一些自定义文件转换为 hadoop 序列文件。

我正在从本地文件中读取字节数组,并将它们作为索引(整数)-数据(字节[])对附加到序列文件中:

InputStream in = new BufferedInputStream(new FileInputStream(localSource));
FileSystem fs = FileSystem.get(URI.create(hDFSDestinationDirectory),conf);
Path sequenceFilePath = new Path(hDFSDestinationDirectory + "/"+ "data.seq");

IntWritable key = new IntWritable();
BytesWritable value = new BytesWritable();
SequenceFile.Writer writer = SequenceFile.createWriter(fs, conf,
            sequenceFilePath, key.getClass(), value.getClass());

     for (int i = 1; i <= nz; i++) 
     byte[] imageData = new byte[nx * ny * 2];
     in.read(imageData);

     key.set(i);
     value.set(imageData, 0, imageData.length);
     writer.append(key, value);
     
IOUtils.closeStream(writer);
in.close();

当我想将文件恢复到初始格式时,我会做完全相反的事情:

    for (int i = 1; i <= nz; i++) 
        reader.next(key, value);
        int byteLength = value.getLength();
        byte[] tempValue = value.getBytes();
        out.write(tempValue, 0, byteLength);
        out.flush();
    

我注意到写入 SequenceFile 几乎比读取要多一个数量级。 我预计写入比读取要慢,但这种差异正常吗?为什么?

更多信息: 我读取的字节数组大小为 2MB(nx=ny=1024 和 nz=128) 我正在伪分布式模式下进行测试。

【问题讨论】:

什么是时间单位的“数量级”? 【参考方案1】:

您正在从本地磁盘读取并写入 HDFS。当您写入 HDFS 时,您的数据可能正在被复制,因此根据您为复制因子设置的内容,它会被物理写入两到三次。

因此,您不仅在写入,而且写入的数据量是您正在读取的数据量的两到三倍。你的写作正在网络上传播。你的读数不是。

【讨论】:

我在伪分布式模式下测试,所以我没有复制也没有网络流量。抱歉没有指出。【参考方案2】:

nxny 是常量吗?

您可能会看到这种情况的一个原因是您的 for 循环的每次迭代都会创建一个新的字节数组。这需要 JVM 为您分配一些堆空间。如果数组足够大,这将是昂贵的,最终你会遇到 GC。不过,我不太确定 HotSpot 可能会做些什么来优化它。

我的建议是创建一个 BytesWritable:

// use DataInputStream so you can call readFully()
DataInputStream in = new DataInputStream(new FileInputStream(localSource));
FileSystem fs = FileSystem.get(URI.create(hDFSDestinationDirectory),conf);
Path sequenceFilePath = new Path(hDFSDestinationDirectory + "/"+ "data.seq");

IntWritable key = new IntWritable();
// create a BytesWritable, which can hold the maximum possible number of bytes
BytesWritable value = new BytesWritable(new byte[maxPossibleSize]);
// grab a reference to the value's underlying byte array
byte byteBuf[] = value.getBytes();
SequenceFile.Writer writer = SequenceFile.createWriter(fs, conf,
        sequenceFilePath, key.getClass(), value.getClass());

for (int i = 1; i <= nz; i++) 
  // work out how many bytes to read - if this is a constant, move outside the for loop
  int imageDataSize nx * ny * 2;
  // read in bytes to the byte array
  in.readFully(byteBuf, 0, imageDataSize);

   key.set(i);
   // set the actual number of bytes used in the BytesWritable object
   value.setSize(imageDataSize);
   writer.append(key, value);


IOUtils.closeStream(writer);
in.close();

【讨论】:

是的 nx, nz 是常数,我试试这个,谢谢你的详细回答。

以上是关于为啥 Hadoop SequenceFile 写入比读取慢得多?的主要内容,如果未能解决你的问题,请参考以下文章

Hadoop SequenceFile数据结构介绍及读写

大数据系列基于MapReduce的数据处理 SequenceFile序列化文件

hadoop FileSystem类和SequenceFile类实例

Hadoop IO操作之SequenceFile 和 MapFile

hadoop 将HDFS上多个小文件合并到SequenceFile里

Hadoop基于文件的数据结构及实例