„Meine Bibliothek befindet sich im Klassenpfad, aber ich erhalte immer noch eine Klasse nicht gefunden-Ausnahme in einem MapReduce-Job“ – Wenn Sie dieses Problem haben, ist dieser Blog für Sie.
Java erfordert, dass sich Drittanbieter- und benutzerdefinierte Klassen im „–classpath“ der Befehlszeile befinden “-Option, wenn die JVM gestartet wird. Das `hadoop`-Wrapper-Shell-Skript erledigt genau dies für Sie, indem es den Klassenpfad aus den Kernbibliotheken erstellt, die sich in /usr/lib/hadoop-0.20/ befinden und /usr/lib/hadoop-0.20/lib/ Verzeichnisse. Mit MapReduce werden die Aufgabenversuche Ihres Jobs jedoch auf Remote-Knoten ausgeführt. Wie weisen Sie einen Remote-Rechner an, Drittanbieter- und benutzerdefinierte Klassen einzuschließen?
MapReduce-Jobs werden in separaten JVMs auf TaskTrackern ausgeführt, und manchmal müssen Sie Bibliotheken von Drittanbietern bei den Versuchen zum Zuordnen/Reduzieren von Aufgaben verwenden. Beispielsweise möchten Sie möglicherweise von Ihren Kartenaufgaben aus auf HBase zugreifen. Eine Möglichkeit, dies zu tun, besteht darin, jede Klasse, die in der einreichbaren JAR verwendet wird, zu verpacken. Sie müssen die ursprüngliche hbase-.jar
entpacken und verpacken Sie alle Klassen in Ihrem einreichbaren Hadoop-Jar. Nicht gut. Tun Sie das nicht:Die Versionskompatibilitätsprobleme werden Sie früher oder später beißen.
Es gibt bessere Möglichkeiten, dasselbe zu tun, indem Sie entweder Ihre JAR-Datei in einen verteilten Cache stellen oder die gesamte JAR-Datei auf den Hadoop-Knoten installieren und TaskTrackers ihren Standort mitteilen.
1. Binden Sie das JAR in die „-libjars ein “-Befehlszeilenoption des Befehls „hadoop jar …“. Das JAR wird im verteilten Cache abgelegt und allen Aufgabenversuchen des Jobs zur Verfügung gestellt. Genauer gesagt finden Sie das JAR in einem der ${mapred.local.dir}/taskTracker/archive/${user.name}/distcache/… Unterverzeichnisse auf lokalen Knoten. Der Vorteil des verteilten Caches besteht darin, dass Ihr JAR bei Ihrem nächsten Programmlauf möglicherweise noch vorhanden ist (zumindest theoretisch:Die Dateien sollten nur dann aus dem verteilten Cache geworfen werden, wenn sie das durch die local.cache definierte Soft-Limit überschreiten .Größe Konfigurationsvariable, standardmäßig 10 GB, aber Ihre tatsächliche Laufleistung kann insbesondere mit den neuesten Sicherheitserweiterungen variieren). Hadoop verfolgt die Änderungen an den verteilten Cache-Dateien, indem es ihren Änderungszeitstempel untersucht.
*Aktualisierung zum Beitrag:Bitte beachten Sie, dass die Punkte 2 und 3 unten ab CDH4 veraltet sind und ab CDH5 nicht mehr unterstützt werden.
2. Fügen Sie die JAR-Datei, auf die verwiesen wird, in das lib-Unterverzeichnis der absendebaren JAR-Datei ein:Ein MapReduce-Job entpackt die JAR-Datei aus diesem Unterverzeichnis in ${mapred.local.dir}/taskTracker/${user.name}/jobcache/$ jobid/jars auf den TaskTracker-Knoten und verweisen Sie Ihre Aufgaben auf dieses Verzeichnis, um die JAR-Datei für Ihren Code verfügbar zu machen. Wenn die JARs klein sind, sich häufig ändern und berufsspezifisch sind, ist dies die bevorzugte Methode.
3. Abschließend können Sie JAR auf den Cluster-Knoten installieren. Am einfachsten ist es, das JAR in $HADOOP_HOME/lib zu platzieren Verzeichnis, da alles aus diesem Verzeichnis eingeschlossen wird, wenn ein Hadoop-Daemon gestartet wird. Da Sie jedoch wissen, dass nur TaskTracker diese im neuen JAR benötigen, ist es besser, die Option HADOOP_TASKTRACKER_OPTS in der Konfigurationsdatei hadoop-env.sh zu ändern. Diese Methode wird bevorzugt, wenn das JAR an den Code gebunden ist, der auf den Knoten ausgeführt wird, wie z. B. HBase.
HADOOP_TASKTRACKER_OPTS="-classpath<colon-separated-paths-to-your-jars>"
Starten Sie die TastTrackers neu, wenn Sie fertig sind. Vergessen Sie nicht, das JAR zu aktualisieren, wenn sich die zugrunde liegende Software ändert.
Alle oben genannten Optionen wirken sich nur auf den Code aus, der auf den verteilten Knoten ausgeführt wird. Wenn Ihr Code, der den Hadoop-Job startet, dieselbe Bibliothek verwendet, müssen Sie die JAR-Datei auch in die Umgebungsvariable HADOOP_CLASSPATH aufnehmen:
HADOOP_CLASSPATH="<colon-separated-paths-to-your-jars>"
Beachten Sie, dass der Klassenpfad ab Java 1.6 auf Verzeichnisse wie „/path/to/your/jars/*“ verweisen kann “, der alle JARs aus dem angegebenen Verzeichnis aufnimmt.
Die gleichen Leitprinzipien gelten für native Codebibliotheken, die auf den Knoten ausgeführt werden müssen (JNI- oder C++-Pipes). Sie können sie mit den „-Dateien in den verteilten Cache legen ”-Optionen, fügen Sie sie in Archivdateien ein, die mit den “-archives “-Option oder installieren Sie sie auf den Cluster-Knoten. Wenn der Linker für dynamische Bibliotheken ordnungsgemäß konfiguriert ist, sollte der native Code für Ihre Aufgabenversuche verfügbar gemacht werden. Sie können die Umgebung der Ausführungsaufgaben des Jobs auch explizit ändern, indem Sie die Variablen JAVA_LIBRARY_PATH oder LD_LIBRARY_PATH angeben:
hadoop jar <your jar> [main class] -D mapred.child.env="LD_LIBRARY_PATH=/path/to/your/libs" ...