본문 바로가기
Old Posts/Hadoop

[Hadoop] Windows 환경에서 IOException 발생 케이스 - winutils.exe 파일 없음

by A6K 2022. 3. 5.

윈도우 환경에서 Hadoop이나 HBase, Spark를 사용할 때 다음 에러를 만나게 되는 경우가 있다.

21:49:57.792 [main] ERROR org.apache.hadoop.util.Shell - Failed to locate the winutils binary in the hadoop binary path
java.io.IOException: Could not locate executable null\bin\winutils.exe in the Hadoop binaries.
	at org.apache.hadoop.util.Shell.getQualifiedBinPath(Shell.java:382) ~[hadoop-common-2.7.4.jar:?]
	at org.apache.hadoop.util.Shell.getWinUtilsPath(Shell.java:397) [hadoop-common-2.7.4.jar:?]
	at org.apache.hadoop.util.Shell.<clinit>(Shell.java:390) [hadoop-common-2.7.4.jar:?]
	at org.apache.hadoop.util.StringUtils.<clinit>(StringUtils.java:80) [hadoop-common-2.7.4.jar:?]
	at org.apache.hadoop.conf.Configuration.getBoolean(Configuration.java:1437) [hadoop-common-2.7.4.jar:?]
	at org.apache.hadoop.hbase.HBaseConfiguration.checkDefaultsVersion(HBaseConfiguration.java:73) [hbase-common-1.3.6.jar:1.3.6]
	at org.apache.hadoop.hbase.HBaseConfiguration.addHbaseResources(HBaseConfiguration.java:87) [hbase-common-1.3.6.jar:1.3.6]
	at org.apache.hadoop.hbase.HBaseConfiguration.create(HBaseConfiguration.java:102) [hbase-common-1.3.6.jar:1.3.6]

 winutils.exe 파일을 찾을 수 없는 것 같다.

원인

아마도 윈도우에서만 발생하는 것 같다. 내 경우에는 HBase 클라이언트를 이용한 애플리케이션을 작성하다가 발생했다. 근데 에러만 찍히고 애플리케이션은 또 잘 동작한다.

왜 발생하는지 스택 트레이스에 남은 코드들을 확인해봤다.

public boolean getBoolean(String name, boolean defaultValue) {
    String valueString = this.getTrimmed(name);
    if (null != valueString && !valueString.isEmpty()) {
        if (StringUtils.equalsIgnoreCase("true", valueString)) {
            return true;
        } else {
            return StringUtils.equalsIgnoreCase("false", valueString) ? false : defaultValue;
        }
    } else {
        return defaultValue;
    }
 }

일단 HBaseConfiguration 코드에서 Configuration.getBoolean() 메소드를 호출했다. 이 메소드 안에서 StringUtils 클래스의 static 메서드를 불러다 쓴다. 아마도 이 때 StringUtils 클래스의 로딩이 된 것 같다.

static {
    ENV_VAR_PATTERN = Shell.WINDOWS ? WIN_ENV_VAR_PATTERN : SHELL_ENV_VAR_PATTERN;
    emptyStringArray = new String[0];
}

 

StringUtils 클래스의 정의를 보면 이런 static 블럭이 있다. StringUtils 클래스가 로딩되다가 이 부분이 실행된 것 같다. 이 블럭을 보면 윈도우일 경우를 체크하는데, Shell 클래스가 또 로딩된다.

static {
    WINDOWS = osType == Shell.OSType.OS_TYPE_WIN;
    SOLARIS = osType == Shell.OSType.OS_TYPE_SOLARIS;
    MAC = osType == Shell.OSType.OS_TYPE_MAC;
    FREEBSD = osType == Shell.OSType.OS_TYPE_FREEBSD;
    LINUX = osType == Shell.OSType.OS_TYPE_LINUX;
    OTHER = osType == Shell.OSType.OS_TYPE_OTHER;
    PPC_64 = System.getProperties().getProperty("os.arch").contains("ppc64");
    HADOOP_HOME_DIR = checkHadoopHome();
    WINUTILS = getWinUtilsPath();
    isSetsidAvailable = isSetsidSupported();
    TOKEN_SEPARATOR_REGEX = WINDOWS ? "[|\n\r]" : "[ \t\n\r\f]";
}

여기에도 static 블럭이 있는데 문제의 getWinUtilsPath() 메서드가 호출된다.

public static final String getWinUtilsPath() {
    String winUtilsPath = null;
    try {
        if (WINDOWS) {
            winUtilsPath = getQualifiedBinPath("winutils.exe");
        }
    } catch (IOException var2) {
        LOG.error("Failed to locate the winutils binary in the hadoop binary path", var2);
    }

    return winUtilsPath;
}

public static final String getQualifiedBinPath(String executable) throws IOException {
    String fullExeName = HADOOP_HOME_DIR + File.separator + "bin" + File.separator + executable;
    File exeFile = new File(fullExeName);
    if (!exeFile.exists()) {
        throw new IOException("Could not locate executable " + fullExeName + " in the Hadoop binaries.");
    } else {
        return exeFile.getCanonicalPath();
    }
}

WinUtils.exe 파일을 찾는데 HADOOP_HOME_DIR의 bin 디렉토리에서 찾는다. 가장 첫 번째 문제는 HADOOP_HOME 경로가 지정되지 않았고, WinUtils.exe 파일도 없다. 이걸 해결해주면 에러가 더 이상 발생하지 않는다.

해결방법

HADOOP_HOME으로 사용할 디렉토리를 생성하고 환경변수로 설정해준다. [Window] + [Q] 버튼을 눌러서 "시스템 환경 변수 편집"을 입력한다.

고급탭이 기본으로 열린다. [환경변수(N)] 버튼을 누른다.

현재 설정되어있는 환경변수들이 보인다. 새로만들기 버튼을 눌러서 HADOOP_HOME을 추가해주자.

변수 이름으로 "HADOOP_HOME"을 입력하고 하둡 홈 디렉토리로 사용할 경로를 입력해준다.

이제 HADOOP_HOME 디렉토리 밑에 bin 디렉토리를 생성하고, https://github.com/steveloughran/winutils/blob/master/hadoop-2.7.1/bin/winutils.exe 파일을 다운로드해서 bin 디렉토리에 위치시킨다.

그리고 다시 컴파일 하거나 IDE를 다시 시작하면 HADOOP_HOME 디렉토리가 잡히고 에러가 발생하지 않게 된다.

 

댓글