Hive Metastore HA avec DBTokenStore : Failed to initialize master key
By WORMS David
21 juil. 2016
- Catégories
- Big Data
- DevOps & SRE
- Tags
- Infrastructure
- Hive
- Bug
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) parrawStore = baseHandler.getMS();
oùbaseHandler
estHiveMetaStore.HMSHandler
- dans
HiveMetaStore.HMSHandler.getMS
, la méthodegetMS
(edit : code source désormais indisponible) return une instance dethreadLocalMS.get()
ounewRawStore() 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éthodegetMasterKey
, 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.