„Moja biblioteka znajduje się w ścieżce klas, ale nadal otrzymuję wyjątek Nie znaleziono klasy w zadaniu MapReduce” – Jeśli masz ten problem, ten blog jest dla Ciebie.
Java wymaga, aby klasy zewnętrzne i zdefiniowane przez użytkownika znajdowały się w wierszu poleceń „–classpath ” opcja po uruchomieniu JVM. Skrypt powłoki `hadoop` robi dokładnie to za Ciebie, budując ścieżkę klas z podstawowych bibliotek znajdujących się w /usr/lib/hadoop-0.20/ i /usr/lib/hadoop-0.20/lib/ katalogi. Jednak dzięki MapReduce próby zadań zadania są wykonywane na zdalnych węzłach. Jak powiedzieć zdalnemu komputerowi, aby zawierał klasy innych firm i klasy zdefiniowane przez użytkownika?
Zadania MapReduce są wykonywane w oddzielnych maszynach JVM na TaskTrackers i czasami trzeba użyć bibliotek innych firm w próbach mapowania/redukowania. Na przykład możesz chcieć uzyskać dostęp do HBase z poziomu zadań mapy. Jednym ze sposobów, aby to zrobić, jest spakowanie każdej klasy używanej w możliwym do przesłania pliku JAR. Będziesz musiał rozpakować oryginalny plik hbase-.jar
i przepakuj wszystkie klasy do swojego słoika Hadoop, który można przesłać. Niedobrze. Nie rób tego:problemy ze zgodnością wersji prędzej czy później cię dotkną.
Są lepsze sposoby na zrobienie tego samego poprzez umieszczenie swojego jara w rozproszonej pamięci podręcznej lub zainstalowanie całego JARa na węzłach Hadoop i poinformowanie TaskTrackerów o ich lokalizacji.
1. Dołącz plik JAR do „-libjars ” opcja wiersza poleceń polecenia `hadoop jar …`. Słoik zostanie umieszczony w rozproszonej pamięci podręcznej i będzie dostępny dla wszystkich prób zadania zadania. Dokładniej, JAR znajdziesz w jednym z ${mapred.local.dir}/taskTracker/archive/${user.name}/distcache/… podkatalogi w węzłach lokalnych. Zaletą rozproszonej pamięci podręcznej jest to, że twój jar może nadal tam być przy następnym uruchomieniu programu (przynajmniej teoretycznie:pliki powinny zostać wyrzucone z rozproszonej pamięci podręcznej tylko wtedy, gdy przekroczą miękki limit zdefiniowany przez local.cache .rozmiar zmienna konfiguracyjna, domyślnie 10 GB, ale rzeczywisty przebieg może się różnić, szczególnie w przypadku najnowszych ulepszeń bezpieczeństwa). Hadoop śledzi zmiany w rozproszonych plikach pamięci podręcznej, sprawdzając ich sygnaturę czasową modyfikacji.
*Aktualizacja do publikacji:pamiętaj, że pozycje 2 i 3 poniżej są przestarzałe, począwszy od CDH4 i nie będą już obsługiwane, począwszy od CDH5.
2. Dołącz plik JAR, do którego się odwołuje, w podkatalogu lib pliku JAR, który można przesłać:zadanie MapReduce rozpakuje plik JAR z tego podkatalogu do ${mapred.local.dir}/taskTracker/${user.name}/jobcache/$ jobid/słoiki w węzłach TaskTracker i skieruj swoje zadania do tego katalogu, aby udostępnić JAR swojemu kodowi. Jeśli pliki JAR są małe, często się zmieniają i są dostosowane do konkretnego stanowiska, jest to preferowana metoda.
3. Na koniec możesz zainstalować plik JAR na węzłach klastra. Najprostszym sposobem jest umieszczenie pliku JAR w $HADOOP_HOME/lib katalog, ponieważ wszystko z tego katalogu jest uwzględniane podczas uruchamiania demona Hadoop. Ponieważ jednak wiesz, że tylko TaskTrackers będą potrzebować nowego JARa, lepszym sposobem jest zmodyfikowanie opcji HADOOP_TASKTRACKER_OPTS w pliku konfiguracyjnym hadoop-env.sh. Ta metoda jest preferowana, jeśli JAR jest powiązany z kodem działającym w węzłach, takim jak HBase.
HADOOP_TASKTRACKER_OPTS="-classpath<colon-separated-paths-to-your-jars>"
Po zakończeniu uruchom ponownie TastTrackers. Nie zapomnij zaktualizować jara, gdy zmieni się oprogramowanie bazowe.
Wszystkie powyższe opcje wpływają tylko na kod działający na rozproszonych węzłach. Jeśli Twój kod uruchamiający zadanie Hadoop korzysta z tej samej biblioteki, musisz również dołączyć plik JAR do zmiennej środowiskowej HADOOP_CLASSPATH:
HADOOP_CLASSPATH="<colon-separated-paths-to-your-jars>"
Zwróć uwagę, że począwszy od Java 1.6 ścieżka klas może wskazywać na katalogi takie jak „/ścieżka/do/twój/jars/* ”, który pobierze wszystkie pliki JAR z podanego katalogu.
Te same zasady przewodnie dotyczą bibliotek kodu natywnego, które muszą być uruchamiane na węzłach (potoki JNI lub C++). Możesz umieścić je w rozproszonej pamięci podręcznej za pomocą „-plików ”, dołącz je do plików archiwum określonych za pomocą opcji „-archive ” lub zainstaluj je na węzłach klastra. Jeśli linker biblioteki dynamicznej jest poprawnie skonfigurowany, kod natywny powinien zostać udostępniony dla twoich prób zadania. Możesz także zmodyfikować środowisko prób uruchomienia zadania zadania, określając zmienne JAVA_LIBRARY_PATH lub LD_LIBRARY_PATH:
hadoop jar <your jar> [main class] -D mapred.child.env="LD_LIBRARY_PATH=/path/to/your/libs" ...