복붙노트

[HADOOP] 큰 (> 1GB) BytesWritable 값 크기로 SequenceFile을 만들 때 NegativeArraySizeException

HADOOP

큰 (> 1GB) BytesWritable 값 크기로 SequenceFile을 만들 때 NegativeArraySizeException

나는 큰 Hadoop SequenceFile을 만드는 다른 방법을 시도했다. 간단히 하나의 짧은 (<100bytes) 키이지만 하나의 큰 (> 1GB) 값 (BytesWriteable).

다음 샘플은 기본적으로 작동합니다.

https://svn.apache.org/repos/asf/hadoop/common/trunk/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-jobclient/src/test/java/org/apache/hadoop/mapred/BigMapOutput.java

총 3GB보다 큰 임의의 길이의 키와 값을 씁니다.

그러나 내가하려는 것은 아닙니다. 그래서 hadoop 2.2.0 API를 사용하여 다음과 같이 수정했습니다.

      Path file = new Path("/input");
      SequenceFile.Writer writer = SequenceFile.createWriter(conf,
      SequenceFile.Writer.file(file),
      SequenceFile.Writer.compression(CompressionType.NONE),
      SequenceFile.Writer.keyClass(BytesWritable.class),
      SequenceFile.Writer.valueClass(BytesWritable.class));
      int numBytesToWrite = fileSizeInMB * 1024 * 1024;
      BytesWritable randomKey = new BytesWritable();
      BytesWritable randomValue = new BytesWritable();
      randomKey.setSize(1);
      randomValue.setSize(numBytesToWrite);
      randomizeBytes(randomValue.getBytes(), 0, randomValue.getLength());
      writer.append(randomKey, randomValue);
      writer.close();

fileSizeInMB> 700MB이면 다음과 같은 오류가 발생합니다.

java.lang.NegativeArraySizeException
        at  org.apache.hadoop.io.BytesWritable.setCapacity(BytesWritable.java:144)
        at  org.apache.hadoop.io.BytesWritable.setSize(BytesWritable.java:123)
        ...

이 오류에 대해 논의되었지만 해결책은 없습니다. int (2 ^ 32)는 2GB만큼 클 수 있으며 700MB에서 실패하지 않아야합니다.

이러한 큰 값의 SequenceFile을 만드는 다른 대안이 있다면 조언하십시오. 입력 스트림에서 바이트 []로 IOutils.read와 같은 다른 접근법을 시도했지만 힙 크기 또는 OOME이 있습니다.

해결법

  1. ==============================

    1.대신 ArrayPrimitiveWritable을 사용하십시오.

    대신 ArrayPrimitiveWritable을 사용하십시오.

    BytesWritable에서 새로운 용량을 설정하면 int overflow가 발생합니다.

    public void setSize(int size) {
        if (size > getCapacity()) {
           setCapacity(size * 3 / 2);
        }
        this.size = size;
    }
    

    700 Mb * 3> 2Gb = int 오버 플로우!

    결과적으로 700MB 이상의 직렬화를 BytesWritable에 직렬화 해제 할 수는 없지만 쓰기 및 직렬화 할 수는 있습니다.

  2. ==============================

    2.BytesWritable을 사용하려는 경우 옵션이 용량을 충분히 높게 설정하므로 700MB뿐만 아니라 2GB를 사용합니다.

    BytesWritable을 사용하려는 경우 옵션이 용량을 충분히 높게 설정하므로 700MB뿐만 아니라 2GB를 사용합니다.

    randomValue.setCapacity(numBytesToWrite);
    randomValue.setSize(numBytesToWrite); // will not resize now
    

    이 버그는 최근 Hadoop에서 수정되었으므로 최신 버전에서는 해당 기능 없이도 작동합니다.

    public void setSize(int size) {
      if (size > getCapacity()) {
        // Avoid overflowing the int too early by casting to a long.
        long newSize = Math.min(Integer.MAX_VALUE, (3L * size) / 2L);
        setCapacity((int) newSize);
      }
      this.size = size;
    }
    
  3. from https://stackoverflow.com/questions/24127304/negativearraysizeexception-when-creating-a-sequencefile-with-large-1gb-bytesw by cc-by-sa and MIT license