Почему запись Hadoop SequenceFile намного медленнее, чем чтение? - PullRequest
0 голосов
/ 02 марта 2012

Я конвертирую некоторые свои собственные файлы в файлы последовательности hadoop, используя Java API.

Я читаю байтовые массивы из локального файла и добавляю их в файл последовательности в виде пар индекса (целое число)- Данные (байт []):

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 занимает почти на порядок больше, чем чтение. Я ожидаю, что запись будет медленнее, чем чтение, но нормально ли это различие?Почему?

Подробнее: Чтение байтовых массивов размером 2 МБ (nx = ny = 1024 и nz = 128)
Я тестирую в псевдораспределенном режиме.

Ответы [ 2 ]

1 голос
/ 21 марта 2012

Являются ли nx и ny постоянными?

Одна из причин, по которой вы можете видеть это, заключается в том, что каждая итерация вашего цикла 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();
1 голос
/ 02 марта 2012

Вы читаете с локального диска и пишете в HDFS.Когда вы пишете в HDFS, ваши данные, вероятно, копируются, поэтому они физически записываются два или три раза в зависимости от того, что вы установили для коэффициента репликации.

То есть вы не только пишете, но и записываете в два-три раза больше данных, которые читаете.И ваши записи идут по сети.Ваши чтения не.

...