“Thư viện của tôi nằm trong classpath nhưng tôi vẫn gặp ngoại lệ Class Not Found trong công việc MapReduce” - Nếu bạn gặp sự cố này, blog này là dành cho bạn.
Java yêu cầu các lớp của bên thứ ba và do người dùng xác định phải nằm trên “- classpath của dòng lệnh ”Khi JVM được khởi chạy. Tập lệnh shell wrapper `hadoop` thực hiện chính xác điều này cho bạn bằng cách xây dựng classpath từ các thư viện lõi nằm trong /usr/lib/hadoop-0.20/ và /usr/lib/hadoop-0.20/lib/ các thư mục. Tuy nhiên, với MapReduce, các nỗ lực công việc của bạn được thực hiện trên các nút từ xa. Làm cách nào để bạn yêu cầu một máy từ xa bao gồm các lớp của bên thứ ba và do người dùng xác định?
Các công việc MapReduce được thực thi trong các JVM riêng biệt trên TaskTrackers và đôi khi bạn cần sử dụng thư viện của bên thứ ba trong các lần thử tác vụ bản đồ / giảm bớt. Ví dụ:bạn có thể muốn truy cập HBase từ bên trong các tác vụ bản đồ của mình. Một cách để làm điều này là đóng gói mọi lớp được sử dụng trong JAR của bảng đệ trình. Bạn sẽ phải giải nén hbase-.jar
gốc và đóng gói lại tất cả các lớp trong jar Hadoop có thể gửi của bạn. Không tốt. Đừng làm điều này:Các vấn đề về khả năng tương thích phiên bản sẽ sớm xảy ra với bạn.
Có nhiều cách tốt hơn để làm điều tương tự bằng cách đặt jar của bạn vào bộ nhớ cache phân tán hoặc cài đặt toàn bộ JAR trên các nút Hadoop và cho TaskTrackers biết về vị trí của chúng.
1. Bao gồm JAR trong “ -libjars ”Tùy chọn dòng lệnh của lệnh` hadoop jar… `. Bình sẽ được đặt trong bộ đệm phân tán và sẽ sẵn sàng cho tất cả các lần thử nhiệm vụ của công việc. Cụ thể hơn, bạn sẽ tìm thấy JAR ở một trong $ {mapred.local.dir} / taskTracker / archive / $ {user.name} / distcache /… thư mục con trên các nút cục bộ. Ưu điểm của bộ đệm phân tán là jar của bạn có thể vẫn ở đó trong lần chạy chương trình tiếp theo của bạn (ít nhất là về lý thuyết:Các tệp chỉ nên được loại bỏ khỏi bộ đệm phân tán khi chúng vượt quá giới hạn mềm được xác định bởi local.cache . kích thước biến cấu hình, mặc định là 10GB, nhưng số dặm thực tế của bạn có thể thay đổi đặc biệt với các cải tiến bảo mật mới nhất). Hadoop theo dõi các thay đổi đối với các tệp bộ đệm ẩn được phân phối bằng cách kiểm tra dấu thời gian sửa đổi của chúng.
* Cập nhật để đăng:Xin lưu ý rằng mục 2 và 3 bên dưới không được dùng nữa kể từ CDH4 và sẽ không còn được hỗ trợ kể từ CDH5.
2. Bao gồm JAR được tham chiếu trong thư mục con lib của JAR có thể gửi:Một công việc MapReduce sẽ giải nén JAR từ thư mục con này thành $ {mapred.local.dir} / taskTracker / $ {user.name} / jobcache / $ jobid / lọ trên các nút TaskTracker và trỏ các nhiệm vụ của bạn đến thư mục này để cung cấp JAR cho mã của bạn. Nếu các JAR nhỏ, thay đổi thường xuyên và theo công việc cụ thể thì đây là phương pháp ưu tiên.
3. Cuối cùng, bạn có thể cài đặt JAR trên các nút cụm. Cách dễ nhất là đặt JAR vào $ HADOOP_HOME / lib thư mục vì mọi thứ từ thư mục này được bao gồm khi khởi động trình nền Hadoop. Tuy nhiên, vì bạn biết rằng chỉ TaskTrackers mới cần những JAR mới này, nên cách tốt hơn là sửa đổi tùy chọn HADOOP_TASKTRACKER_OPTS trong tệp cấu hình hadoop-env.sh. Phương pháp này được ưu tiên nếu JAR được gắn với mã chạy trên các nút, như HBase.
HADOOP_TASKTRACKER_OPTS="-classpath<colon-separated-paths-to-your-jars>"
Khởi động lại TastTrackers khi bạn hoàn tất. Đừng quên cập nhật jar khi phần mềm bên dưới thay đổi.
Tất cả các tùy chọn trên chỉ ảnh hưởng đến mã chạy trên các nút phân tán. Nếu mã khởi chạy công việc Hadoop của bạn sử dụng cùng một thư viện, bạn cũng cần bao gồm JAR trong biến môi trường HADOOP_CLASSPATH:
HADOOP_CLASSPATH="<colon-separated-paths-to-your-jars>"
Lưu ý rằng bắt đầu với Java 1.6 classpath có thể trỏ đến các thư mục như “ / path / to / your / jar / * ”Sẽ chọn tất cả các JAR từ thư mục đã cho.
Các nguyên tắc hướng dẫn tương tự cũng áp dụng cho các thư viện mã gốc cần được chạy trên các nút (đường ống JNI hoặc C ++). Bạn có thể đưa chúng vào bộ nhớ đệm phân tán với “ -files ”, Đưa chúng vào các tệp lưu trữ được chỉ định với“ -bộ lưu trữ ”Hoặc cài đặt chúng trên các nút cụm. Nếu trình liên kết thư viện động được định cấu hình đúng cách, mã gốc sẽ được cung cấp cho các nỗ lực tác vụ của bạn. Bạn cũng có thể sửa đổi môi trường của các lần thử nhiệm vụ đang chạy của công việc một cách rõ ràng bằng cách chỉ định các biến JAVA_LIBRARY_PATH hoặc LD_LIBRARY_PATH:
hadoop jar <your jar> [main class] -D mapred.child.env="LD_LIBRARY_PATH=/path/to/your/libs" ...