Edited at

EC2 A1インスタンスでApache Hadoopをビルドしてみる

気がつけばARMアーキテクチャのインスタンスがAWSで使えるようになっていたので、Apache Hadoopのビルドを試してみます。

今回はAmazon Linux、a1.xlargeを起動します。

$ uname -a

Linux ip-172-31-9-141.us-west-2.compute.internal 4.14.77-81.59.amzn2.aarch64 #1 SMP Mon Nov 12 21:28:57 UTC 2018 aarch64 aarch64 aarch64 GNU/Linux

CPU情報を確認してみますが、Featuresが少なくて壮観です

$ cat /proc/cpuinfo

processor : 0
BogoMIPS : 166.66
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x0
CPU part : 0xd08
CPU revision : 3

processor : 1
BogoMIPS : 166.66
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x0
CPU part : 0xd08
CPU revision : 3

processor : 2
BogoMIPS : 166.66
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x0
CPU part : 0xd08
CPU revision : 3

processor : 3
BogoMIPS : 166.66
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x0
CPU part : 0xd08
CPU revision : 3

Hadoopをビルドする場合、通常では、-Pnativeのオプションを有効にしてC/C++のライブラリ(native library)もビルドするのですが、今回は簡単のため、native libraryのビルドは無効にします。Native libraryのビルドを無効化してもHadoopが動かなくなることはないのですが、HDFS Short-Circuit Local Readsなどの、native libraryに依存する高速化の機能が使えなくなります。

また、Hadoopをビルドするときには yum install で入ってくれないライブラリをいくつかインストールする必要があります。その代表例がApache Maven(>= 3.3)とProtocol Buffers(= 2.5.0)なのですが、Protocol Buffersについては、現在のAmazon Linuxだと yum install protobuf* でいとも簡単に入ってくれます。Mavenは手でインストールしてあげる必要がありますが、現状A1インスタンスは東京リージョンでサポートしていないので、ASF(Apache Software Founcation)のミラーサイトのうち近い所から意識してダウンロードしてあげないとダウンロードに時間がかかります。ダウンロード元のインスタンスから以下のコマンドを実行することで、最も近いミラーサイトを取得できます。

$ curl -s 'https://www.apache.org/dyn/closer.cgi?as_json=1' | python -c "import sys, json; print json.load(sys.stdin)['preferred']"

http://us.mirrors.quenda.co/apache/

情報元: https://stackoverflow.com/questions/21534797/finding-the-closest-apache-software-foundation-mirror-programatically

ここまで準備が終わったところでHadoopをビルドしてみると、YARN CSI(Container Storage Interface)のビルドで失敗します。

[ERROR] Failed to execute goal org.xolstice.maven.plugins:protobuf-maven-plugin:0.5.1:compile-custom (default) on project hadoop-yarn-csi: Missing:

[ERROR] ----------
[ERROR] 1) io.grpc:protoc-gen-grpc-java:exe:linux-aarch_64:1.15.1
[ERROR]
[ERROR] Try downloading the file manually from the project website.
[ERROR]
[ERROR] Then, install it using the command:
[ERROR] mvn install:install-file -DgroupId=io.grpc -DartifactId=protoc-gen-grpc-java -Dversion=1.15.1 -Dclassifier=linux-aarch_64 -Dpackaging=exe -Dfile=/path/to/file
[ERROR]
[ERROR] Alternatively, if you host your own repository you can deploy the file there:
[ERROR] mvn deploy:deploy-file -DgroupId=io.grpc -DartifactId=protoc-gen-grpc-java -Dversion=1.15.1 -Dclassifier=linux-aarch_64 -Dpackaging=exe -Dfile=/path/to/file -Durl=[url] -DrepositoryId=[id]
[ERROR]
[ERROR] Path to dependency:
[ERROR] 1) org.apache.hadoop:hadoop-yarn-csi:jar:3.3.0-SNAPSHOT
[ERROR] 2) io.grpc:protoc-gen-grpc-java:exe:linux-aarch_64:1.15.1
[ERROR]
[ERROR] ----------
[ERROR] 1 required artifact is missing.
[ERROR]
[ERROR] for artifact:
[ERROR] org.apache.hadoop:hadoop-yarn-csi:jar:3.3.0-SNAPSHOT
[ERROR]
[ERROR] from the specified remote repositories:
[ERROR] apache.snapshots.https (https://repository.apache.org/content/repositories/snapshots, releases=true, snapshots=true),
[ERROR] repository.jboss.org (http://repository.jboss.org/nexus/content/groups/public/, releases=true, snapshots=false),
[ERROR] central (https://repo.maven.apache.org/maven2, releases=true, snapshots=false)
[ERROR]
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
[ERROR]
[ERROR] After correcting the problems, you can resume the build with the command
[ERROR] mvn <goals> -rf :hadoop-yarn-csi

io.grpc:protoc-gen-grpc-java:exe:linux-aarch_64:1.15.1 が存在しないと言われています。呼び出し元は以下の通り


hadoop-yarn-project/hadoop-yarn/hadoop-yarn-csi/pom.xml

            <plugin>

<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>${protobuf-maven-plugin.version}</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:3.6.1:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.15.1:exe:${os.detected.classifier}</pluginArtifact>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>

${os.detected.classifier}が利用され、アーキテクチャに対応したartifactを取りに行こうとしますが、io.grpc:protoc-gen-grpc-javaにaarch_64のリリースが存在しないために失敗しています。この問題を解決するには大きく2通りあります。


  • YARN CSIのビルドを諦める

  • 自前で io.grpc:protoc-gen-grpc-java をビルドする

ビルドを諦める場合は、以下の設定から hadoop-yarn-csi を取り除けば完了です。


hadoop-yarn-project/hadoop-yarn/pom.xml

  <modules>

<module>hadoop-yarn-api</module>
<module>hadoop-yarn-common</module>
<module>hadoop-yarn-server</module>
<module>hadoop-yarn-applications</module>
<module>hadoop-yarn-site</module>
<module>hadoop-yarn-client</module>
<module>hadoop-yarn-registry</module>
<module>hadoop-yarn-ui</module>
<module>hadoop-yarn-csi</module>
</modules>

これでは面白くないので、自前でビルドしてみることにしましょう。


  • protobufをビルド

$ git clone https://github.com/google/protobuf.git

$ cd protobuf
$ git checkout v3.5.1.1
$ ./autogen.sh && ./configure && make


  • 環境変数の設定

$ export CXXFLAGS="-I/home/aajisaka/git/protobuf/src -L/home/aajisaka/git/protobuf/src/.libs"

$ export LDFLAGS="$CXXFLAGS"
$ export LD_LIBRARY_PATH="/home/aajisaka/git/protobuf/src"


  • grpc-javaをビルド

$ git clone https://github.com/grpc/grpc-java.git

$ cd grpc-java
$ git checkout v1.15.1
$ ./gradlew build --no-daemon
$ ./gradlew install --no-daemon

参考にした記事

Local repositoryを見ると、pomとexeが正しく配置されていそうに見えます。これでようやくHadoopをビルドできそうです!

$ ls -alh ~/.m2/repository/io/grpc/protoc-gen-grpc-java/1.15.1/

total 3.0M
drwxrwxr-x 2 aajisaka aajisaka 288 Dec 21 06:44 .
drwxrwxr-x 3 aajisaka aajisaka 52 Dec 21 06:44 ..
-rw-rw-r-- 1 aajisaka aajisaka 3.0M Dec 21 06:43 protoc-gen-grpc-java-1.15.1-linux-aarch_64.exe
-rw-rw-r-- 1 aajisaka aajisaka 559 Dec 21 01:40 protoc-gen-grpc-java-1.15.1-linux-aarch_64.exe.lastUpdated
-rw-rw-r-- 1 aajisaka aajisaka 2.1K Dec 21 06:44 protoc-gen-grpc-java-1.15.1.pom
-rw-rw-r-- 1 aajisaka aajisaka 513 Dec 21 01:40 protoc-gen-grpc-java-1.15.1.pom.lastUpdated
-rw-rw-r-- 1 aajisaka aajisaka 40 Dec 21 01:40 protoc-gen-grpc-java-1.15.1.pom.sha1
-rw-rw-r-- 1 aajisaka aajisaka 181 Dec 21 01:40 _remote.repositories

ビルド!

$ mvn install -DskipTests

(snip)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 17:19 min
[INFO] Finished at: 2018-12-21T07:07:36Z
[INFO] ------------------------------------------------------------------------

めでたしめでたし。

しかしながら、現実にHadoopをARMアーキテクチャで利用するためにはnative libraryのビルドも必要でしょうし、本当にARMに変更してコスパが良くなるのかベンチマークする必要があるでしょう。特に、CPUのハードウェア命令に頼った処理をしている場合は注意が必要です。例えば、HDFSのデータ暗号化にはAES-NIを、HDFS Erasure CodingにはISA-Lをそれぞれ高速化のために利用しているため、ARMでこれらの処理を充分高速に実行できるかは未知数です。

気が向いたらnative libraryのビルドも頑張ってみます。


追記

$ openssl speed -evp aes-256-ctr

Doing aes-256-ctr for 3s on 16 size blocks: 57872810 aes-256-ctr's in 3.00s
Doing aes-256-ctr for 3s on 64 size blocks: 38476148 aes-256-ctr's in 3.00s
Doing aes-256-ctr for 3s on 256 size blocks: 16757050 aes-256-ctr's in 3.00s
Doing aes-256-ctr for 3s on 1024 size blocks: 5071541 aes-256-ctr's in 3.00s
Doing aes-256-ctr for 3s on 8192 size blocks: 688484 aes-256-ctr's in 3.00s
OpenSSL 1.0.2k-fips 26 Jan 2017
built on: reproducible build, date unspecified
options:bn(64,64) md2(int) rc4(ptr,char) des(idx,cisc,16,int) aes(partial) idea(int) blowfish(ptr)
compiler: gcc -I. -I.. -I../include -fPIC -DOPENSSL_PIC -DZLIB -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -DKRB5_MIT -DL_ENDIAN -Wall -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -Wa,--noexecstack -DPURIFY -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM
The 'numbers' are in 1000s of bytes per second processed.
type 16 bytes 64 bytes 256 bytes 1024 bytes 8192 bytes
aes-256-ctr 308654.99k 820824.49k 1429934.93k 1731085.99k 1880020.31k

参考: https://medium.com/@voluntas/cpu-%E3%81%AE-aes-%E9%AB%98%E9%80%9F%E5%8C%96-21459540ed8