1

Java コードを使用して haddop ファイルにアクセスすると、スタック オーバーフロー エラーが発生します。

import java.io.InputStream;
import java.net.URL;
import org.apache.hadoop.fs.FsUrlStreamHandlerFactory;
import org.apache.hadoop.io.IOUtils;
public class URLCat 
{
    static 
    {
            URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());
    }

    public static void main(String[] args) throws Exception 
    {
        InputStream in = null;
        try 
        {
            in = new URL(args[0]).openStream();
            IOUtils.copyBytes(in, System.out, 4096, false);
        }
        finally 
        {
            IOUtils.closeStream(in);
        }
    }
}

私はEclipseを使用してこのコードをデバッグし、行を知りました

in = new URL(args[0]).openStream();

生成エラー。

Hadoopファイルパスを渡すことでこのコードを実行しています

 hdfs://localhost/user/jay/abc.txt

例外 (コメントから取得) :

Exception in thread "main" java.lang.StackOverflowError
  at java.nio.Buffer.<init>(Buffer.java:174) 
  at java.nio.ByteBuffer.<init>(ByteBuffer.java:259) 
  at java.nio.HeapByteBuffer.<init>(HeapByteBuffer.java:52) 
  at java.nio.ByteBuffer.wrap(ByteBuffer.java:350) 
  at java.nio.ByteBuffer.wrap(ByteBuffer.java:373) 
  at java.lang.StringCoding$StringEncoder.encode(StringCoding.java:237) 
  at java.lang.StringCoding.encode(StringCoding.java:272) 
  at java.lang.String.getBytes(String.java:946) 
  at java.io.UnixFileSystem.getBooleanAttributes0(Native Method) 
  .. stack trace truncated ..
4

2 に答える 2

3

1) これは、hadoop が提供する FSURLStreamHandlerFactory クラスのバグによるものです。このクラスを含む最新の jar ではバグが修正されていることに注意してください。

2) このファイルは、hadoop-common-2.0.0-cdh4.2.1.jar にあります。問題を完全に理解するには、java.net.URL クラスがどのように機能するかを理解する必要があります。

URL オブジェクトの働き

「URLStreamHandler」を渡さずにコンストラクターのいずれかを使用して新しい URL を作成すると (その値に null を渡すか、パラメーターとして URLStreamHandler オブジェクトを取らないコンストラクターを呼び出して)、内部的に getURLStreamHandler() というメソッドを呼び出します。このメソッドは URLStreamHandler オブジェクトを返し、メンバーを設定します

URL クラスの変数。

このオブジェクトは、「http」、「file」などの特定のスキームの接続を構築する方法を知っています。この URLStreamHandler は、呼び出されたファクトリによって構築されます。

URLStreamHandlerFactory.

3) 上記の問題の例では、次の静的メソッドを呼び出すことにより、URLStreamHandlerFactory が「FsUrlStreamHandlerFactory」に設定されました。

    URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());

そのため、新しい URL を作成すると、この「FSUrlStreamHandlerFactory」を使用して、その createURLStreamHandler(protocol) メソッドを呼び出して、この新しい URL の URLStreamHandler オブジェクトを作成します。

このメソッドは、FileSystem クラスの loadFileSystems() というメソッドを呼び出します。loadFileSystems() メソッドは ServiceLoader.load("FileSystem.class") を呼び出すため、クラスパスとそのエントリを読んでいます。

4) 各 jar は URL オブジェクトとして処理されることに注意してください。つまり、各 jar の URL オブジェクトは ClassLoader によって内部的に作成されます。クラスローダーは URLStreamHandler オブジェクトを提供します

これらの jar の URL を作成するときに、これらの URL が設定した「FSUrlStreamHandlerFactory」の影響を受けないようにします。これは、URL に既に「URLStreamHandler」があるためです。私たちは

jar ファイルを処理する場合、クラス ローダーは「URLStreamHandler」を「sun.net.www.protocol.jar.Handler」タイプとして設定します。

5) FileSystem 実装クラスの jar ファイル内のエントリを読み取るために、「sun.net.www.protocol.jar.Handler」は、各エントリの URL オブジェクトを作成する必要があります。

URLStreamHandler オブジェクトなしで URL コンストラクターを呼び出します。すでに URLStreamHandlerFactory を「FSUrlStreamHandlerFactory」として定義しているため、createURLStreamHandler を呼び出します。

(プロトコル) メソッドは無期限に再帰を引き起こし、「StackOverflowException」につながります。

このバグは、Hadoop コミッターによって「HADOOP-9041」として知られています。リンクはhttps://issues.apache.org/jira/browse/HADOOP-9041です。

私はこれがやや複雑であることを知っています。

要するに、この問題の解決策を以下に示します。

1) このバグを修正した最新の jar hadoop-common-2.0.0-cdh4.2.1.jar を使用します。

また

2) URLStreamHandlerFactory を設定する前に、次のステートメントを静的ブロックに入れます。

      static {
               FileSystem.getFileSystemClass("file",new Configuration()); 
               URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());
             } 

static ブロック内の最初のステートメントは FsUrlStreamHandlerFactory に依存せず、file:// のデフォルト ハンドラーを使用して META-INF/services/*.FileSystem ファイル内のファイル全体を読み取ることに注意してください。

于 2014-04-22T21:21:48.727 に答える
1

回避策があります。

Hadoop の世界の現在の状態 (2014 年 1 月) に詳しい人が私たちを啓発したり、動作を説明したりしてくれれば幸いです。

Haddop The Definitive Guide Third Edition Tom White から URLCat を実行しようとしたときに、同じ StackOverflowError に遭遇しました

Cloudera QuickStart 4.4.0 および 4.3.0 に問題があります

jdk1.6.0_32 と jdk1.6.0_45 の両方を使用する

この問題は、java.net.URL の下にある org.apache.hadoop.fs.FileSystem の初期化/クラスの読み込み中に発生します。ある種の再帰的な例外処理が開始されています。私はそれを追跡するために最善を尽くしました。このパスは、sun.misc.CompoundEnumeration.nextElement() を呼び出す java.util.ServiceLoader につながります。 残念ながら、sun.misc.CompoundEnumeration のソースは jdk src.zip に含まれていません。 java パッケージ sun.misc

別の実行パスを介してエラーをトリガーしようとして、回避策を思いつきました...

StreamHandlerFactory を登録する前に org.apache.hadoop.fs.FileSystem.getFileSystemClass(String, Configuration) を呼び出すことで、StackOverflowError につながる状況を回避できます。

これは、静的初期化ブロックを変更することで実行できます (上記の元のリストを参照)。

   static {
        Configuration conf = new Configuration();
        try {
            FileSystem.getFileSystemClass("file", conf);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        };
        URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());
    }

これは、この静的ブロックの内容を main() に移動することによっても実現できます。

FsUrlStreamHandlerFactory を使用したスタックオーバーフローで、2011 年 8 月からこのエラーへの別の参照を見つけました。

より多くの Hadoop 初心者がこの問題に遭遇していないことに、私は非常に当惑しています ... Hadoop の本を購入してください ... Cloudera QuickStart をダウンロードしてください ... 非常に単純な例を試してみてください ...失敗!?

より経験豊富な人々からの洞察をいただければ幸いです。

于 2014-01-17T23:59:18.800 に答える