一、 異常分析
最近, 在使用服務器運行 MapReduce 的 jar 包時報瞭如下錯誤:
[root@hadoop102 jars]# hadoop jar /opt/module/jars/mr-1.0-SNAPSHOT-jar-with-dependencies.jar com.atguigu.hive.project.gulivideo.ETLDriver /video/2008/0222 /gulivideo
Exception in thread "main" java.io.IOException: No FileSystem for scheme: d
at org.apache.hadoop.fs.FileSystem.getFileSystemClass(FileSystem.java:2644)
at org.apache.hadoop.fs.FileSystem.createFileSystem(FileSystem.java:2651)
at org.apache.hadoop.fs.FileSystem.access$200(FileSystem.java:92)
at org.apache.hadoop.fs.FileSystem$Cache.getInternal(FileSystem.java:2687)
at org.apache.hadoop.fs.FileSystem$Cache.get(FileSystem.java:2669)
at org.apache.hadoop.fs.FileSystem.get(FileSystem.java:371)
at org.apache.hadoop.fs.Path.getFileSystem(Path.java:295)
at org.apache.hadoop.mapreduce.lib.input.FileInputFormat.setInputPaths(FileInputFormat.java:500)
at com.atguigu.mr.wordcount.WordcountDriver.main(WordcountDriver.java:49)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.hadoop.util.RunJar.run(RunJar.java:221)
at org.apache.hadoop.util.RunJar.main(RunJar.java:136)
由於我想要執行的是 com.atguigu.hive.project.gulivideo.ETLDriver 這個類, 但是我的 ETLDriver 類中並沒有指定 D 盤的代碼。
看報錯信息說是 FileInputFormat.setInputPaths 設置的時候出了錯, 可是代碼中是這麼設置的:
FileInputFormat.setInputPaths(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
是從 args 參數中拿出來輸入路徑和輸出路徑。
試了很多方式也沒有解決掉, 所以犯了難。
最終還是找了大神請教了下, 原來我的 pom.xml 文件中, 之前的代碼留下了這樣的一段:
... ...
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.atguigu.mr.wordcount.WordcountDriver</mainClass>
</manifest>
</archive>
... ...
由於這個位置指定了一個 WordcountDriver 類, 導致使用 Maven 編譯的時候, 編譯了 WordcountDriver 這個類, 而上傳到服務器後, 本來我想執行的 ETLDriver 類也沒有被執行, 而是執行了 pom.xml 文件中指定的 WordcountDriver 類。 而這個類中在設置輸入路徑的時候, 指向的是 D 盤的一個目錄。 所以纔出現了這個報錯。
二、 解決方式
2.1 解決方式一
在 pom.xml 中不指定具體類, Maven 直接編譯所有的, 然後去服務器上執行的時候, 可以指定任何一個存在的類;
此時的執行語句是:
hadoop jar /opt/module/jars/mr-1.0-SNAPSHOT-jar-with-dependencies.jar com.atguigu.hive.project.gulivideo.ETLDriver /video/2008/0222 /gulivideo
即需要指定執行的類名;
2.2 解決方式二
在 pom.xml 中指定這個 ETLDriver 的類名, 但是在服務器上執行的時候, 就不要指定具體類名了, 因爲 jar 包中只允許調用 pom.xml 中指定的類了
此時的執行語句是:
hadoop jar /opt/module/jars/mr-1.0-SNAPSHOT-jar-with-dependencies.jar /video/2008/0222 /gulivideo
即不需要再指定要執行的類的全限定名; 如果非要指定, 那麼程序會認爲指定的類名是第一個參數, 原本想要設置的輸入路徑是第二個參數(輸出路徑), 就會報錯: 輸出路徑已存在;
三、 總結
一旦執行 MapReduce 程序報了這種錯誤, 就要檢查代碼中是否設置了 D 盤的路徑, 結合報錯信息看, 是輸入路徑設置的, 就檢查輸入路徑是否設置就可以快速定位並解決掉這個異常;