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가지의 경우가 있습니다.
- hive.metastore.schema.verification=false 로 설정된 상태에서, 스키마 버전을 Fetch 하려고 할 때 어떤 이유에서든지(예를들면, Network 단절 등) Database 로부터 Null 값을 리턴 받게되는 경우
- 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 버전을 사용하는 것으로 업그레이드를 고려하시거나 이 글에 공개된 버그 부분을 패치하여 사용하는 것으로 근본적인 문제를 해결할 수 있겠습니다.