Hive Metastore contains multiple versions Exception 해결방법

Hive 를 사용하다 보면 아래 로그와 같이 Hive 의 Metastore 에 버전이 여러 개 존재한다고 하는 MetaException(message:Metastore contains multiple versions) 에러를 종종 만나게 됩니다.

아래 로그는 실제 에러가 발생한 이후, Hive 를 통하여 어떠한 쿼리를 실행하였을 때 발생하는 에러 로그 입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2016-07-02 16:14:33,330 ERROR metastore.HiveMetaStore (HiveMetaStore.java:main(4224)) - Metastore Thrift Server threw an exception...
MetaException(message:Metastore contains multiple versions)
        at org.apache.hadoop.hive.metastore.ObjectStore.getMSchemaVersion(ObjectStore.java:5861)
        at org.apache.hadoop.hive.metastore.ObjectStore.getMetaStoreSchemaVersion(ObjectStore.java:5823)
        at org.apache.hadoop.hive.metastore.ObjectStore.checkSchema(ObjectStore.java:5782)
        at org.apache.hadoop.hive.metastore.ObjectStore.verifySchema(ObjectStore.java:5770)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at org.apache.hadoop.hive.metastore.RawStoreProxy.invoke(RawStoreProxy.java:108)
        at com.sun.proxy.$Proxy0.verifySchema(Unknown Source)
        at org.apache.hadoop.hive.metastore.HiveMetaStore$HMSHandler.getMS(HiveMetaStore.java:408)
        at org.apache.hadoop.hive.metastore.HiveMetaStore$HMSHandler.createDefaultDB(HiveMetaStore.java:446)
        at org.apache.hadoop.hive.metastore.HiveMetaStore$HMSHandler.init(HiveMetaStore.java:333)
        at org.apache.hadoop.hive.metastore.HiveMetaStore$HMSHandler.<init>(HiveMetaStore.java:293)
        at org.apache.hadoop.hive.metastore.RetryingHMSHandler.<init>(RetryingHMSHandler.java:54)
        at org.apache.hadoop.hive.metastore.RetryingHMSHandler.getProxy(RetryingHMSHandler.java:59)
        at org.apache.hadoop.hive.metastore.HiveMetaStore.newHMSHandler(HiveMetaStore.java:4085)
        at org.apache.hadoop.hive.metastore.HiveMetaStore.startMetaStore(HiveMetaStore.java:4287)
        at org.apache.hadoop.hive.metastore.HiveMetaStore.main(HiveMetaStore.java:4221)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at org.apache.hadoop.util.RunJar.main(RunJar.java:212)

위와 같은 에러가 발생한 경우에 Hive 의 Meta Store 의 VERSION 테이블 정보를 확인해 보면, 아래와 같이 SCHEMA_VERSION 이 두개 이상 존재하는 것을 확인할 수 있습니다.

1
2
3
4
5
6
7
8
9
USE metastore;
SELECT * FROM VERSION;
+--------+----------------+-------------------------------------+
| VER_ID | SCHEMA_VERSION | VERSION_COMMENT                     |
+--------+----------------+-------------------------------------+
|      1 | 1.2.0          | Set by MetaStore hadoop@아이피        |
|    17  | 1.2.0          | Set by MetaStore hadoop@아이피        |
+--------+----------------+-------------------------------------+
2 row in set (0.00 sec)

이 상황이 발생하면 이후에 실행되는 어떠한 쿼리도 전혀 실행되지 않는 상황을 만나게 되며 이것을 해결하기 위한 솔루션은 아래와 같습니다.

정상화를 위한 임시조치

일단 발생한 문제의 긴급 해결책은 VERSION 테이블의 VER_ID 컬럼 값이 1 이 아닌 다른 Record 를 지워주는 것 입니다.

1
2
delete from VERSION where VER_ID !='1';
commit;

하지만, 위와 같은 임시 조치를 통해 문제를 해결하였다고 하더라도 운영 중 다시 Multiple contains versions 에러를 만나게 될 것입니다. 따라서 문제를 유발 시킬 수 있는 Root Cause 를 해결할 수 있는 방법은 아래와 같습니다.

근본적인 해결책

위 상황과 같이 VER_ID 값이 중복으로 생길 수 있는 Root Cause 는 다음과 같은 2가지의 경우가 있습니다.

  1. hive.metastore.schema.verification=false 로 설정된 상태에서, 스키마 버전을 Fetch 하려고 할 때 어떤 이유에서든지(예를들면, Network 단절 등) Database 로부터 Null 값을 리턴 받게되는 경우
  2. hive.metastore.schema.verification=true 로 설정된 상태에서 Metastore 스키마 버전이 Hive Distribution 과 같은 경우

1번의 경우는 hive.metastore.schema.verification 의 설정값을 true 로 바꾸는 것으로 해결 할 수 있습니다. 하지만 Hive 의 버전에 따라 설정만으로 해결되지 않는 2번의 경우를 만날 수 있으며 관련 버그는 1.2.0 버전에서 Fixed 되었습니다(이슈:HIVE-9749).

버그가 존재하는 1.13 코드는 아래와 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
private synchronized void checkSchema() throws MetaException {
  // recheck if it got verified by another thread while we were waiting
  if (isSchemaVerified.get()) {
    return;
  }
  boolean strictValidation =
    HiveConf.getBoolVar(getConf(), HiveConf.ConfVars.METASTORE_SCHEMA_VERIFICATION);
  // read the schema version stored in metastore db
  String schemaVer = getMetaStoreSchemaVersion();
  if (schemaVer == null) {
    // metastore has no schema version information
    if (strictValidation) {
          throw new MetaException("Version information not found in metastore. ");
        } else {
          LOG.warn("Version information not found in metastore. "
              + HiveConf.ConfVars.METASTORE_SCHEMA_VERIFICATION.toString() +
              " is not enabled so recording the schema version " +
              MetaStoreSchemaInfo.getHiveSchemaVersion());
          setMetaStoreSchemaVersion(MetaStoreSchemaInfo.getHiveSchemaVersion(),
              "Set by MetaStore");
      }
  } else {
    // metastore schema version is different than Hive distribution needs
    if (strictValidation) {
      if (!schemaVer.equalsIgnoreCase(MetaStoreSchemaInfo.getHiveSchemaVersion())) {
        throw new MetaException("Hive Schema version "
            + MetaStoreSchemaInfo.getHiveSchemaVersion() +
            " does not match metastore's schema version " + schemaVer +
            " Metastore is not upgraded or corrupt");
      } else {
        LOG.warn("Metastore version was " + schemaVer + " " +
            HiveConf.ConfVars.METASTORE_SCHEMA_VERIFICATION.toString() +
            " is not enabled so recording the new schema version " +
            MetaStoreSchemaInfo.getHiveSchemaVersion());
        setMetaStoreSchemaVersion(MetaStoreSchemaInfo.getHiveSchemaVersion(),
            "Set by MetaStore");
      }
    }
  }
  isSchemaVerified.set(true);
  return;

버그가 해결된 1.2.0 코드는 아래와 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
private synchronized void checkSchema() throws MetaException {
  // recheck if it got verified by another thread while we were waiting
  if (isSchemaVerified.get()) {
    return;
  }
  boolean strictValidation =
    HiveConf.getBoolVar(getConf(), HiveConf.ConfVars.METASTORE_SCHEMA_VERIFICATION);
  // read the schema version stored in metastore db
  String schemaVer = getMetaStoreSchemaVersion();
  if (schemaVer == null) {
    if (strictValidation) {
      throw new MetaException("Version information not found in metastore. ");
    } else {
      LOG.warn("Version information not found in metastore. "
          + HiveConf.ConfVars.METASTORE_SCHEMA_VERIFICATION.toString() +
          " is not enabled so recording the schema version " +
          MetaStoreSchemaInfo.getHiveSchemaVersion());
      setMetaStoreSchemaVersion(MetaStoreSchemaInfo.getHiveSchemaVersion(),
        "Set by MetaStore " + USER + "@" + HOSTNAME);
    }
  } else {
    // metastore schema version is different than Hive distribution needs
    if (schemaVer.equalsIgnoreCase(MetaStoreSchemaInfo.getHiveSchemaVersion())) {
      LOG.debug("Found expected HMS version of " + schemaVer);
    } else {
      if (strictValidation) {
        throw new MetaException("Hive Schema version "
            + MetaStoreSchemaInfo.getHiveSchemaVersion() +
            " does not match metastore's schema version " + schemaVer +
            " Metastore is not upgraded or corrupt");
      } else {
        LOG.error("Version information found in metastore differs " + schemaVer +
            " from expected schema version " + MetaStoreSchemaInfo.getHiveSchemaVersion() +
            ". Schema verififcation is disabled " +
            HiveConf.ConfVars.METASTORE_SCHEMA_VERIFICATION + " so setting version.");
        setMetaStoreSchemaVersion(MetaStoreSchemaInfo.getHiveSchemaVersion(),
          "Set by MetaStore " + USER + "@" + HOSTNAME);
      }
    }
  }
  isSchemaVerified.set(true);
  return;
}

마치며

일단 문제가 발생하게되면 Hive 를 통하여 실행되는 모든 쿼리가 동작하지 않으므로 중복된 VERSION 정보를 지우는 방법을 통해 빠르게 해결을 해야하며, 가능하면 버그가 패치된 Hive 버전을 사용하는 것으로 업그레이드를 고려하시거나 이 글에 공개된 버그 부분을 패치하여 사용하는 것으로 근본적인 문제를 해결할 수 있겠습니다.


Popit은 페이스북 댓글만 사용하고 있습니다. 페이스북 로그인 후 글을 보시면 댓글이 나타납니다.