Hive Metastore HA avec DBTokenStore: Failed to initialize master key

Hive Metastore HA avec DBTokenStore: Failed to initialize master key

By WORMS David

21 juil. 2016

Catégories : Big Data, DevOps & SRE | Tags : Hive, Bug, Infrastructure

Cette article décrit ma petite aventure autour d’une erreur au démarrage du Hive Metastore. Elle se reproduit dans un environnement précis qui est celui d’une installation sécurisée, entendre avec Kerberos, en haute disponibilité avec le stockage des delegation token dans une base de données. La version de Hive est la 1.2 packagée dans la distribution Hortonworks 2.4.2.

Le stockage des delegation token est définit par la propriété hive.cluster.delegation.token.store.class. Les choix disponibles sont Zookeeper, la base de données du Metastore et la mémoire. Autant Cloudera qu’Hortonworks recommandent l’utilisation de la base de données soit la valeur org.apache.hadoop.hive.thrift.DBTokenStore.

L’erreur en question se produit au lancement du Metastore et porte la signature suivante :

java.io.IOException: Failed to initialize master key
    at org.apache.hadoop.hive.thrift.TokenStoreDelegationTokenSecretManager.startThreads(TokenStoreDelegationTokenSecretManager.java:213)
    at org.apache.hadoop.hive.thrift.HiveDelegationTokenManager.startDelegationTokenSecretManager(HiveDelegationTokenManager.java:96)
    at org.apache.hadoop.hive.metastore.HiveMetaStore.startMetaStore(HiveMetaStore.java:6031)
    at org.apache.hadoop.hive.metastore.HiveMetaStore.main(HiveMetaStore.java:5945)
    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.run(RunJar.java:221)
    at org.apache.hadoop.util.RunJar.main(RunJar.java:136)
Caused by: java.lang.reflect.InvocationTargetException
    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.thrift.TokenStoreDelegationTokenSecretManager.startThreads(TokenStoreDelegationTokenSecretManager.java:211)
    ... 9 more
Caused by: org.apache.hadoop.hive.thrift.DelegationTokenStore$TokenStoreException: java.lang.NoSuchMethodException: org.apache.hadoop.hive.metastore.HiveMetaStore$HMSHandler.addMasterKey(java.lang.String)
    at org.apache.hadoop.hive.thrift.DBTokenStore.invokeOnRawStore(DBTokenStore.java:158)
    at org.apache.hadoop.hive.thrift.DBTokenStore.addMasterKey(DBTokenStore.java:42)
    at org.apache.hadoop.hive.thrift.TokenStoreDelegationTokenSecretManager.logUpdateMasterKey(TokenStoreDelegationTokenSecretManager.java:193)
    at org.apache.hadoop.security.token.delegation.AbstractDelegationTokenSecretManager.updateCurrentKey(AbstractDelegationTokenSecretManager.java:335)
    ... 14 more
Caused by: java.lang.NoSuchMethodException: org.apache.hadoop.hive.metastore.HiveMetaStore$HMSHandler.addMasterKey(java.lang.String)
    at java.lang.Class.getMethod(Class.java:1670)
    at org.apache.hadoop.hive.thrift.DBTokenStore.invokeOnRawStore(DBTokenStore.java:148)
    ... 17 more
Exception in thread "main" java.io.IOException: Failed to initialize master key
    at org.apache.hadoop.hive.thrift.TokenStoreDelegationTokenSecretManager.startThreads(TokenStoreDelegationTokenSecretManager.java:213)
    at org.apache.hadoop.hive.thrift.HiveDelegationTokenManager.startDelegationTokenSecretManager(HiveDelegationTokenManager.java:96)
    at org.apache.hadoop.hive.metastore.HiveMetaStore.startMetaStore(HiveMetaStore.java:6031)
    at org.apache.hadoop.hive.metastore.HiveMetaStore.main(HiveMetaStore.java:5945)
    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.run(RunJar.java:221)
    at org.apache.hadoop.util.RunJar.main(RunJar.java:136)
Caused by: java.lang.reflect.InvocationTargetException
    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.thrift.TokenStoreDelegationTokenSecretManager.startThreads(TokenStoreDelegationTokenSecretManager.java:211)
    ... 9 more
Caused by: org.apache.hadoop.hive.thrift.DelegationTokenStore$TokenStoreException: java.lang.NoSuchMethodException: org.apache.hadoop.hive.metastore.HiveMetaStore$HMSHandler.addMasterKey(java.lang.String)
    at org.apache.hadoop.hive.thrift.DBTokenStore.invokeOnRawStore(DBTokenStore.java:158)
    at org.apache.hadoop.hive.thrift.DBTokenStore.addMasterKey(DBTokenStore.java:42)
    at org.apache.hadoop.hive.thrift.TokenStoreDelegationTokenSecretManager.logUpdateMasterKey(TokenStoreDelegationTokenSecretManager.java:193)
    at org.apache.hadoop.security.token.delegation.AbstractDelegationTokenSecretManager.updateCurrentKey(AbstractDelegationTokenSecretManager.java:335)
    ... 14 more
Caused by: java.lang.NoSuchMethodException: org.apache.hadoop.hive.metastore.HiveMetaStore$HMSHandler.addMasterKey(java.lang.String)
    at java.lang.Class.getMethod(Class.java:1670)
    at org.apache.hadoop.hive.thrift.DBTokenStore.invokeOnRawStore(DBTokenStore.java:148)
    ... 17 more

Ok, le message lancé en stdout est plutot clair :

java.io.IOException: Failed to initialize master key Caused by: org.apache.hadoop.hive.thrift.DelegationTokenStore$TokenStoreException: java.lang.NoSuchMethodException: org.apache.hadoop.hive.metastore.HiveMetaStore$HMSHandler.addMasterKey

Une fois nos manches retroussées, plongeons dans le code source. Hortonworks publie sur GitHub le code source de tous les composants de sa distribution. A chaque version de distribution correspond sous Git un tag associé. Hive pour HDP 2.4.2 se rappatrie sur notre poste local avec les commandes :

git clone https://github.com/hortonworks/hive-release/blob/HDP-2.4.2.0-tag
git checkout HDP-2.4.2.0-tag

En effet, pas de fonction HiveMetaStore$HMSHandler.addMasterKey en 2.4.2. On retrouve trace de cette fonction dans la class ObjectStore du même package. En Hive version 1.3 comme 2.1, la situation ne semble pas avoir bougé. Dans les logs, on constate bien que c’est la class ObjectStore qui est référencée :

metastore.HiveMetaStore - 0: Opening raw store with implemenation class:org.apache.hadoop.hive.metastore.ObjectStore

Donc d’un point de vue configuration, le paramètre est bien transmis depuis la configuration et tout devrait être OK. L’erreur est appelée dans la classe DBTokenStore ligne 42 par le code :

return (Integer)invokeOnRawStore("addMasterKey", new Object[]{s},String.class);

Puis à nouveau à la ligne 156 par le code :

return rawStore.getClass().getMethod(methName, paramTypes).invoke(rawStore, params)

Cherchons donc à trouver comment rawStore est construit :

  • il arrive au travers de la méthode DBTokenStore.init
  • pas très sur ou init est appelé
  • mais après une courte recherche, objectStore est instantié dans HiveAuthFactory par rawStore = baseHandler.getMS();baseHandler est HiveMetaStore.HMSHandler
  • dans HiveMetaStore.HMSHandler.getMS, la méthode getMS return une instance de threadLocalMS.get() ou newRawStore() si null
  • cette dernière, newRawStore, s’alimente de la propriété rawStoreClassName
  • cette propriété est initialisée à partir de la configuration
    rawStoreClassName = hiveConf.getVar(HiveConf.ConfVars.METASTORE_RAW_STORE_IMPL);
  • la valeur par défaut est declarée dans HiveConf METASTORE_RAW_STORE_IMPL("hive.metastore.rawstore.impl", "org.apache.hadoop.hive.metastore.ObjectStore",...)
  • on revient à la class ObjectStore, qui contient bien notre méthode getMasterKey, alors que se passe-t-il donc ?

En re-parcourant le code source, on constate que HiveAuthFactory, où le rawstore est construit et passé à la fonction startDelegationTokenSecretManager, s’applique au HiveServer2. Hum, se pourrait-il qu’il existe un équivalent pour le Metastore ?

Une recherche avec startDelegationTokenSecretManager nous conduit à nouveau sur le HiveMetaStore et là que lit-on :

delegationTokenManager.startDelegationTokenSecretManager(
            conf, baseHandler, ServerMode.METASTORE);

Avec baseHandler construit un peu plus haut de la manière suivante :

HMSHandler baseHandler = new HiveMetaStore.HMSHandler(
          "new db based metaserver", conf, false);

La signature de startDelegationTokenSecretManager est la suivante :

public void startDelegationTokenSecretManager(Configuration conf, Object hms, ServerMode smode) throws IOException

N’importe quel objet peut être passé en second argument ce qui est logique puisque Hive fait appel aux outils de réflexion.

S’inspirant de HiveAuthFactory, on constate que le rawStore est lui-même obtenu du baseHandler. Donc le paramètre n’est pas baseHandler mais bien baseHandler.getMS().

Ainsi, HiveMetaStore en ligne 6031 devrait ressembler à :

delegationTokenManager.startDelegationTokenSecretManager(conf, baseHandler.getMS(), ServerMode.METASTORE);

S’agit maintenant de compiler tout ça.

La commande mvn clean package -DskipTests -Phadoop-2 ne passe pas du premier coup. Elle ne passera d’ailleurs jamais. N’étant intéressé que par la compilation de la jar associée au Metastore, prenons l’option de rapidement corriger les erreurs de compilation. Heureusement il n’y en aura qu’une. Elle consiste à supprimer toutes les références à la classe CallerContext dans Hadoop23Shims. Après ça, Maven ne compile pas l’ensemble des projets mais va suffisamment loin pour générer la jar du MetaStore.

En terme de déploiement, tout n’est pas si simple non plus. Remplacer la jar en question ne suffit pas car une autre jar chargée précédemment contient elle aussi les classes impactées. Je pris la solution de réécrire la variable d’environnement HADOOP_CLASSPATH en la préfixant par notre jar nouvellement importée. Dans le fichier “/usr/hdp/current/hive-metastore/bin/ext/metastore.sh”, ajouter :

export HADOOP_CLASSPATH="/usr/hdp/2.4.2.0-258/hive/lib/hive-metastore.jar:$HADOOP_CLASSPATH"

avant la ligne :

export HADOOP_OPTS="$HIVE_METASTORE_HADOOP_OPTS $HADOOP_OPTS"

Exécuter la commande hive --service metastore et le MetaStore démarre.

Il semble que ce problème soit toujours présent dans la branche master du Hive Metastore. Toutefois, il n’était pas présent dans la précédente release HDP 2.4.0.

Remise à jour : Les liens dans l’article pourraient être cassés.

Canada - Morocco - France

International locations

10 rue de la Kasbah
2393 Rabbat
Canada

Nous sommes une équipe passionnées par l'Open Source, le Big Data et les technologies associées telles que le Cloud, le Data Engineering, la Data Sciencem le DevOps…

Nous fournissons à nos clients un savoir faire reconnu sur la manière d'utiliser les technologies pour convertir leurs cas d'usage en projets exploités en production, sur la façon de réduire les coûts et d'accélérer les livraisons de nouvelles fonctionnalités.

Si vous appréciez la qualité de nos publications, nous vous invitons à nous contacter en vue de coopérer ensemble.