概要
AWS Batchのジョブ設定には、VCPUという項目がある。
設定の名称からすると、コンテナ内から見えるCPU数が変わるのではないか?という期待を持ってしまいがち。
しかし、この設定の実態はただの優先度設定である (docker runの--cpu-sharesオプションにマップされている)。
よって、ここに何を設定したとしても、コンテナ内からは、Dockerホストに実装されている全てのCPUコアが見える。
失敗例
OpenMPなどの並列化プラットフォームを利用すると、デフォルトでは、システムに実装されているCPU数分のスレッドが起動する動作になっていることが多い。
そのような動作をするプログラムを動かす際、以下のような(間違った)設定をしたとする。
-
ジョブ定義:
VCPU=2、メモリ8GiB
※「全スレッド共有で4GiB使用し、さらに1スレッドごとに2GiBのメモリを使用する」という設計のプログラムを動かすものとする。
※2スレッド動作時は、4 + 2 * 2で8GiB必要となる。 -
コンピューティング環境:
m4.16xlarge (32物理コア・ 256 GiBメモリ)
設定時の想定では、16コンテナで32スレッドが起動し、16 * 8 = 128GiBのメモリが消費される。
しかしこの場合、実際には、16コンテナ * 32スレッド(物理コア数分) = 512スレッドが起動する。
発生する問題
-
事故パターン1 OOM
512スレッド * 2GiBだけでも1TiBのメモリが必要になるが、動作しているEC2インスタンスには256GiBしか実装されていない。
そこで、OOM Killerさんが目覚める。_人人人人人人_
> 突然の死 <
 ̄Y^Y^Y^Y^Y^Y^ ̄ -
事故パターン2 性能劣化
スレッドごとに必要なメモリが少なく、OOMが起きなかったとする。
それでも、処理の大半が演算の場合、CPUの奪い合い(コンテキストスイッチ祭り)が発生する。_人人人人人人人_
> 無駄に遅い <
 ̄Y^Y^Y^Y^Y^Y^Y^ ̄ただし、この動作は、インスタンスに対して起動中のコンテナが少ない場合にはメリットとなるので、一長一短。
コンテナがCPU性能を目いっぱい使うので処理がすぐ終わり、ジョブが無くなったインスタンスがスケールインすることでコストが下がる。
大抵の場合はメリットのほうが大きいかも。
どうすりゃいいのか
-
スレッド数に比例して消費メモリが(大きく)増える設計/実装は避ける
-
上記が無理なら、起動するスレッド数を固定する
ハードコードではなく、環境変数経由で指定できるようにして、ジョブ定義で調整するとベター。
OpenMPならデフォルトでOMP_NUM_THREADS環境変数によるスレッド数指定に対応している。