Hive Metastore HA avec DBTokenStore : Failed to initialize master key

Hive Metastore HA avec DBTokenStore : Failed to initialize master key

Vous appréciez notre travail......nous recrutons !

Ne ratez pas nos articles sur l'open source, le big data et les systèmes distribués, fréquence faible d’un email tous les deux mois.

Cet 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 (lien est désormais brisé, supprimé par Cloudera depuis l’écriture de cet article) :

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 (edit : code source désormais indisponible) en 2.4.2. On retrouve trace de cette fonction dans la class ObjectStore (edit : code source désormais indisponible) 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 (edit : code source désormais indisponible) par le code :

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

Puis à nouveau à la ligne 156 (edit : code source désormais indisponible) 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 (edit : code source désormais indisponible) par rawStore = baseHandler.getMS();baseHandler est HiveMetaStore.HMSHandler
  • dans HiveMetaStore.HMSHandler.getMS, la méthode getMS (edit : code source désormais indisponible) return une instance de threadLocalMS.get() ou newRawStore() si null
  • cette dernière, newRawStore (edit : code source désormais indisponible), s’alimente de la propriété rawStoreClassName
  • cette propriété est initialisée à partir de la configuration (edit : code source désormais indisponible) rawStoreClassName = hiveConf.getVar(HiveConf.ConfVars.METASTORE_RAW_STORE_IMPL);
  • la valeur par défaut est declarée dans HiveConf (edit : code source désormais indisponible) 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 (edit : code source désormais indisponible), 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 (edit : code source désormais indisponible) 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 (edit : code source désormais indisponible). 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 à la date d’écriture de cet article. Toutefois, il n’était pas présent dans la précédente release HDP 2.4.0 (edit : code source désormais indisponible).

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

Partagez cet article

Canada - Maroc - France

Nous sommes une équipe passionnée par l'Open Source, le Big Data et les technologies associées telles que le Cloud, le Data Engineering, la Data Science 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.

Support Ukrain