CDH5対応のSparkをビルドする方法

このエントリはSpark, SQL on Hadoop etc. Advent Calendar 2014 - Qiitaの12/6担当分です。

CDH5対応のSparkバイナリはどこに?

Sparkアプリケーションの開発を行っていると「Hadoopクラスタに接続してxxする」というケースがあると思います。いちいちアプリケーションのJARをアップロードするのは面倒なので、できれば「手元のマシン(Macとか)からリモートのHadoopクラスタに接続してxx」したいところです。
しかし、Hadoopエコシステムのプロダクトはライブラリの依存関係がシビアなため、バージョンやディストリビューションが異なると接続できないことが多いです。(しかも状況によって発生するエラーが異なるので原因究明が大変です。特に、自分のようにHadoopの経験が浅い人間は素直にディストリビューションの標準構成に従っておいたほうが心安らかに暮らせます。)
ところが、残念ながら Downloads | Apache Spark ではCDH5対応のバイナリが配布されていません。
f:id:nobusue:20141206053210p:plain
「んじゃ、Pre-built for CHD4でためしてみっか」というのは時間の無駄なのでやめておきましょう。以下のようなエラーが出てつながりません。

java.io.IOException: Failed on local exception: com.google.protobuf.InvalidProtocolBufferException: Message missing required fields: callId, status; Host Details : local host is: "nobusue-MacBookPro.local/10.0.0.1"; destination host is: "192.168.56.101":8020; 

ではどうするか。
Clouderaのドキュメントによると「ClouderaのリポジトリからRPMDEBなどのパッケージをインストールする」というのが正しい手順のようです。しかし、これでは手元の環境には導入できません。

CDH5版Sparkのソースを入手する

Apache Spark公式で配布されているソースからビルドする場合、CDH5対応のプロファイルが提供されていないため、ビルドオプションをまとめて指定することはできないようです。Hadoopのバージョンなど個別に指定しなければならないとなると面倒ですよね。
幸い、Clouderaがパッケージを生成するためのソースコードを配布しています。こちらですと、デフォルトでCDH5対応のバイナリが生成されるようにビルドスクリプトが修正されていますので楽です。(Clouderaさんに感謝!)
http://archive.cloudera.com/cdh5/cdh/5/
CDHのバージョンごとにソースやバイナリのアーカイブがありますので、利用する環境にあわせて選択しましょう。例えばCDH5.2.1だとこんな感じです。
f:id:nobusue:20141206055409p:plain
"spark-1.1.0-cdh5.2.1-src.tar.gz"が目的のソースアーカイブです。
よく見ると"spark-1.1.0-cdh5.2.1.tar.gz"なんてのもありますが、これはハズレなので間違えないように。

"spark-1.1.0-cdh5.2.1.tar.gz"はどうしてハズレなのか

このファイルはコンパイル済みバイナリの「JARのみ」を配布するためのアーカイブのようです。
実際にダウンロードしてみればわかりますが、spark-submitやspark-shellなどのコマンド実行に必要なシェルスクリプトなどが欠けており、そのあたりを自分で補う必要があるため、かえって手間がかかります。(Spark User MLでも同じような質問が出てました。)

CDH5版Sparkをソースからビルドする

基本的には Redirecting... と同じです。
JDK6以上 / Maven3.0.4以上が必要ですのでインストールしておいてください。また、ドキュメントには記載がありませんがScalaも必要です。

ダウンロードしてきたソースアーカイブを展開し、以下のコマンドを実行します。

$ SCALA_HOME=<YOUR_SCALA_HOME> MAVEN_OPTS="-Xmx2g -XX:MaxPermSize=512M -XX:ReservedCodeCacheSize=512m" mvn -DskipTests clean package

かなり時間がかかりますので気長に待ってください。(自分の環境では30分ほどかかりました。)
また、たまにClouderaのMavenリポジトリがダウンしていてビルドが失敗することがありますが、時間をおいてから再度実行すれば大丈夫だと思います。

2014/12/25追記

配布物のルートにある「make-distribution.sh」を使えば、MAVEN_OPTSなどの設定は省略できます。
また、バイナリアーカイブが必要な場合は「--tgz」を追加すれば生成できます。ファイル名は「spark--bin-.tgz」になります。

$ ./make-distribution.sh --skip-java-test --tgz --name 2.5.0

Java7以上でビルド刷る場合、「--skip-java-test」を指定しておかないと警告がでます。

モジュール構成に関する注意事項

ビルドを実行する前にpom.xmlを確認して、自分が使いたいモジュールが含まれているかチェックしておくことをおすすめします。
例えば spark-1.0.0-cdh5.1.3-src.tar.gz の場合、は以下のようになっています。

<modules>
  <module>core</module>
  <module>bagel</module>
  <module>graphx</module>
  <module>mllib</module>
  <module>tools</module>
  <module>streaming</module>
  <module>repl</module>
  <module>assembly</module>
  <module>external/twitter</module>
  <module>external/kafka</module>
  <module>external/flume</module>
  <module>external/zeromq</module>
  <module>external/mqtt</module>
  <module>examples</module>
</modules>

あれっ、何か変じゃないですか? (つд⊂)ゴシゴシ
そう、SparkSQLが見当たりません。。。どうもサポート対象外なので除外されているようです。
参考) New in CDH 5.1: Apache Spark 1.0 | Cloudera Engineering Blog

これだと「HDFSはCDH5.1だけどSparkSQLを使いたい」という場合に困りますよね。そういう場合にはに以下を追加してください。

  <module>sql/catalyst</module>
  <module>sql/core</module>
  <module>sql/hive</module>

これでspark-shellなどから普通にSparkSQLが使えるようになります。

ビルド実行時のログの最初の方で、ビルド対象のモジュールの一覧が出ます。念のため確認しておいてください。

[INFO] Reactor Build Order:
[INFO]
[INFO] Spark Project Parent POM
[INFO] Spark Project Core
[INFO] Spark Project Bagel
[INFO] Spark Project GraphX
[INFO] Spark Project Streaming
[INFO] Spark Project ML Library
[INFO] Spark Project Tools
[INFO] Spark Project Catalyst
[INFO] Spark Project SQL
[INFO] Spark Project Hive
[INFO] Spark Project REPL
[INFO] Spark Project Assembly
[INFO] Spark Project External Twitter
[INFO] Spark Project External Kafka
[INFO] Spark Project External Flume Sink
[INFO] Spark Project External Flume
[INFO] Spark Project External ZeroMQ
[INFO] Spark Project External MQTT
[INFO] Spark Project Examples

実行してみる

ビルドが問題なく完了すれば、あとはApache Spark公式から落としてきたバイナリと同じように使えます。
テストとしてリモートのHDFSにファイルを書き出してみましょう。

$ bin/spark-shell
Spark assembly has been built with Hive, including Datanucleus jars on classpath
Welcome to
      ____              __
     / __/__  ___ _____/ /__
    _\ \/ _ \/ _ `/ __/  '_/
   /___/ .__/\_,_/_/ /_/\_\   version 1.1.0
      /_/

Using Scala version 2.10.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_72)
Type in expressions to have them evaluated.
Type :help for more information.
14/12/06 07:10:51 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Spark context available as sc.

scala> val people = sc.textFile("examples/src/main/resources/people.txt")
people: org.apache.spark.rdd.RDD[String] = examples/src/main/resources/people.txt MappedRDD[1] at textFile at <console>:12

scala> people.saveAsTextFile("hdfs://192.168.56.101:8020/tmp/people")

例外が出なければ正常に書き込まれているはずです。HueなどでHDFSを確認してみてください。
f:id:nobusue:20141206071744p:plain

すぐに使えるCDH5の環境が手元になくて、手っ取り早く用意したい場合には Cloudera QuickStart VM を利用するのがよいと思います。
ローカル環境のSparkからQuickStart VMHDFSに接続する場合は、こちらなどを参考にネットワークを設定してみてください。

小ネタでしたが、以上です。
次は adachij2002 さんです。よろしくお願いします。