Travis CIのDynamoDB Localを最適化する

2016.02.05

Travis CIのDynamoDB Localを最適化する

こんばんは!
以前に書いた「DynamoDB Local を Travis CI で使う」の続編にあたるエントリです。Travis CIにDynamoDB Localを組み込むまでは前述の記事をご参照ください。

JVM言語(JavaやScala)のCIをTravis CIで行い、かつDynamoDB Localを使用する場合には DynamoDB Localの起動オプションに注意する 必要があります。

プロセス終了(KILL)される問題

前回の記事でScalaのCI環境にDynamoDB Localを組み込みましたが、その設定のままでDynamoDB Localとの結合を行うテストを一定量以上書くと「テスト実行中にテストプロセス(ScalaならSBT)がSIGINTを受け取り強制終了(Killed)させられてしまう」という現象が発生します。
ほとんどの場合、この現象はTravis CIが提供するコンテナのメモリ不足によって起こります。

スクリーンショット 2016-02-05 19.18.53

同じ理由で Exception in thread "Thread-7" java.net.SocketException: Connection reset のような例外が発生することもあります。これは前回の記事で紹介した例外と同じですね。

スクリーンショット 2016-02-05 19.25.45

メモリ不足ということはわかりました。しかしTravis CIのコンテナは3GBのRAMを提供しています(2015年2月現在)。さらにいえばDynamoDB Localを起動しないテストでメモリ不足になったことはほとんどありません。なぜメモリ不足になってしまうのでしょうか。

Travis CIのJVM起動オプションを確認する

このページにデフォルトJVMオプションを記述したGithubへのリンクが貼られています。さっそく確認してみましょう。

# Tweaking for VM equipped with 3GB of RAM
# See also 'default_jvm_s' defined in <%= File.join(node['sbt-extras']['setup_dir'], node['sbt-extras']['script_name']) %>

-Xms2048M
-Xmx2048M
-Xss6M
-XX:MaxPermSize=512M

3GBのRAMを食いつぶさないように、JVMが2GB利用するように設定されています。例えばScalaのCIであれば、このオプションでSBTが起動します(SBTはテストプロセスをForkさせることもできるので少しややこしいですが、それについては前回の記事をご参照ください)。

ところで、DynamoDB LocalもJVM上で動きます。前回の記事で書いた起動コマンドは以下の通りでした。

java -Djava.library.path=/tmp/dynamodb/DynamoDBLocal_lib -jar /tmp/dynamodb/DynamoDBLocal.jar -sharedDb -inMemory &

勘のいい方はもうお分かりかと思いますが、この起動コマンドも前述のデフォルトJVMオプションで起動します。つまり、テスト実行中にヒープ初期/最大値が2GBのJVMプロセスが2つ立ち上がります。DynamoDB Localとテスト実行プロセス(ScalaであればSBT)ですね。
これらのプロセスにより最大で4GBのメモリが使用されます。そのためTravis CIのコンテナRAMを超えて利用しようとしてしまい、プロセスが終了してしまいます。

これを避けるためには、DynamoDB Localの起動時に個別にJVMオプションを渡してあげる必要があります。

対応方法

Travis CIのコンテナのRAMは3GBありますが、もちろんOSから利用されるRAMなどもあるためテストプロセスが利用できるのはもっと少ないです。テストプロセスのJVMオプションをデフォルトのまま使う(-Xms2048)場合には、DynamoDB Localが仕様するメモリをだいたい256〜512MBにしておけばメモリ不足になることがないようです。

前回の記事のDynamoDB Local起動コマンドを次のコマンドに置き換えましょう。

java -Xms256M -Xmx256M -Xss2M -Djava.library.path=/tmp/dynamodb/DynamoDBLocal_lib -jar /tmp/dynamodb/DynamoDBLocal.jar -sharedDb -inMemory &

結果として次のような .travis.yml になりました。

.travis.yml

language: scala
scala:
  - 2.11.7
jdk:
  - oraclejdk8
install:
  - mkdir /tmp/dynamodb
  - wget -O - http://dynamodb-local.s3-website-us-west-2.amazonaws.com/dynamodb_local_latest | tar xz --directory /tmp/dynamodb
before_script:
  - java -Xms256M -Xmx256M -Xss2M -Djava.library.path=/tmp/dynamodb/DynamoDBLocal_lib -jar /tmp/dynamodb/DynamoDBLocal.jar -sharedDb -inMemory &
  - sleep 2

まとめ

Travis CIでDynamoDB Localを使うときにはいくつか注意しなければならないことはありますが、逆に言えば注意するポイントさえ抑えておけば全く問題なく使うことができます。
DynamoDB LocalとTravis CIを使ってどんどん結合テストを書きましょう!ではまた!