HadoopはApache版0.20.2とCloudera版0.20.2+737で互換性がない
いやまあ、バージョンは合わせろよとか、そのくらい常識だとか、言われそうな話なんですけどね。
症状
別のところで構成されてるHadoopクラスタのHDFSにデータを書き込みたくなったので、あるマシン(CentOS5)にSun JDKとHadoopを入れることにしました。インストールが面倒だと思ってた*1のでClouderaさんが作っているというrpmを使うことにした。
既存のHadoopクラスタではバージョン 0.20.2 を使っているっぽかったのでCDH3でOK。
ここからCDH3(beta3)のリポジトリを yum.repos.d に追加して yum update yum 後に yum install hadoop-0.20 hadoop-0.20-libhdfs とかやってインストール。JAVA_HOMEをJDKのパスに設定。CLASSPATHに以下のようにしてhadoop関連のjarを根こそぎぶちこむ。
$ export CLASSPATH=`find /usr/lib/hadoop-0.20 -name '*.jar' | grep -v 'test' | grep -v 'example' | perl -e '@jars=<STDIN>;chomp @jars; print join(":",@jars);'`
その上でhdfsにアクセスできるか試そうと以下のコマンドを実行したところ、残念な感じのエラーになった。
$ hadoop fs -fs hdfs://namenode-server:PORTNUM/ -ls / Bad connection to FS. command aborted. exception: Call to namenode-server/xx.xx.xx.xx:PORTNUM failed on local exception: java.io.EOFException
このときnamenode側のログには以下のような行が出てた。
2011-01-05 11:29:54,203 WARN org.apache.hadoop.ipc.Server: Incorrect header or version mismatch from yy.yy.yy.yy:NNNN got version 4 expected version 3
対処
Apache版の 0.20.2 リリースとCloudera版(CDH)の 0.20.2+737 ではRPCの相互接続性が失われています。
Hadoopクラスタ側がApache版のHadoopを使用している場合、接続しにいく側もおとなしくApache版のHadoopをダウンロードして使いましょう。
原因
しかし 0.20.2 どうしなのにRPCのバージョン互換性がないってどういうこと? という誰もが抱く疑問について調べてみた。というか、以下のあたり調査してみて確信が持てたからApache版を試してみたんだけど。
まずエラーメッセージから core/org/apache/hadoop/ipc/Server.java を眺めてみる。
// core/org/apache/hadoop/ipc/Server.java line 814 if (!HEADER.equals(dataLengthBuffer) || version != CURRENT_VERSION) { //Warning is ok since this is not supposed to happen. LOG.warn("Incorrect header or version mismatch from " + hostAddress + ":" + remotePort + " got version " + version + " expected version " + CURRENT_VERSION); return -1; }
これですね。"ok since this is not supposed to happen." じゃねーよ。俺を笑い死にさせる気か。
さてこの CURRENT_VERSION をまず見てみると、Apache版では以下のような感じ。
// core/org/apache/hadoop/ipc/Server.java line 84 // 1 : Introduce ping and server does not throw away RPCs // 3 : Introduce the protocol into the RPC connection header public static final byte CURRENT_VERSION = 3;
CDH3では以下。
// 1 : Introduce ping and server does not throw away RPCs // 3 : Introduce the protocol into the RPC connection header // 4 : Introduced SASL security layer public static final byte CURRENT_VERSION = 4;
どう見てもバージョンが違います。本当にありがとうございます。あとはこれをRPC Clientが送っていることが確認できればいいわけですね。
// CDH3版 // core/org/apache/hadoop/ipc/Client.java line 609 /* Write the RPC header */ private void writeRpcHeader(OutputStream outStream) throws IOException { DataOutputStream out = new DataOutputStream(new BufferedOutputStream(outStream)); // Write out the header, version and authentication method out.write(Server.HEADER.array()); out.write(Server.CURRENT_VERSION); authMethod.write(out); out.flush(); }
こんな非互換なパッチを同じバージョン番号で当ててリリースするんじゃねーよ。ていうかApache版を見てみるとメソッド名すら元は writeRpcHeader じゃなくて writeHeader だし。本当に勘弁してくれ。
*1:けどそんなことなかったと後で判明