【AWS】【EMR】スポットインスタンスでの安定稼働を目指して（3/3）：処理特性と設定指針

こちらは[フロムスクラッチ Advent Calendar 2017](https://qiita.com/advent-calendar/2017/fromscratch)の18日目の記事です。

```
EEEEEEEEEEEEEEEEEEEE MMMMMMMM         MMMMMMMM RRRRRRRRRRRRRR
E::::::::::::::::::E M:::::::M       M:::::::M R::::::::::::::R
EE:::::EEEEEEEEE:::E M::::::::M     M::::::::M R:::::RRRRRR:::::R
  E::::E       EEEEE M:::::::::M   M:::::::::M RR::::R      R::::R
  E::::E             M::::::M:::M M:::M::::::M   R:::R      R::::R
  E:::::EEEEEEEEEE   M:::::M M:::M:::M M:::::M   R:::RRRRRR:::::R
  E::::::::::::::E   M:::::M  M:::::M  M:::::M   R:::::::::::RR
  E:::::EEEEEEEEEE   M:::::M   M:::M   M:::::M   R:::RRRRRR::::R
  E::::E             M:::::M    MMM    M:::::M   R:::R      R::::R
  E::::E       EEEEE M:::::M           M:::::M   R:::R      R::::R
EE:::::EEEEEEEE::::E M:::::M           M:::::M   R:::R      R::::R
E::::::::::::::::::E M:::::M           M:::::M RR::::R      R::::R
EEEEEEEEEEEEEEEEEEEE MMMMMMM           MMMMMMM RRRRRRR      RRRRRR
```

当記事に興味を持っていただきありがとうございます。

この記事では、AWS EMR利用者向けにスポットインスタンスを使いつつも、それら安定的に稼働させることを目指して私が取り組んでいることを紹介する記事です。前回の記事はこちらです。

・【AWS】【EMR】スポットインスタンスでの安定稼働を目指して（1/3）：スポットインスタンスとは
https://qiita.com/S_Haraguchi/items/92ee6d64a75242742da6
・【AWS】【EMR】スポットインスタンスでの安定稼働を目指して（2/3）：インスタンスフリートを考えるhttps://qiita.com/S_Haraguchi/items/1e2ee16b927a790d46b8

今回は3回目の最終回ですが、前回紹介したインスタンスフリートを用いて、実際にどのように構成を組んでみると良いか、を考えていきたいと思います。

# オプションの検討ポイント
身もふたもないことを言うようですが、最初に検討していただきたいのは、そもそもオンデマンドではダメなのか？と言うことです。安定的に稼働させたい、というのが第一なのであれば絶対そのほうがいいです。インスタンスフリートだからといって落ちない訳ではないですから。
何かの理由で安定性は気にしなければならないのだが、コスト面も・・・という方は以下の検討ポイントについてご覧ください。

## その処理はリトライができるのか？
処理によってリトライが許容されるのかどうか、例えば、データの整合性の面などで、リトライが許されない（またはリトライにコストがかかる）かどうかです。この場合、マスターノードはオンデマンドで構成しておくことが望ましいでしょう。この場合、例えコアノードやタスクノードが落ちてしまったとしても、マスターノードが生きていれば処理は継続されるからです。
代わりに、コアノードやタスクノードでインスタンスフリートを検討するなどのコスト削減方法を考えたほうが良いでしょう。

## その処理は時間制約があるのか？
例えば、その処理の完了を前提とする後続のバッチ処理がxx時に開始するから、それまでに必ず終わってなければならない、というような制約があるかどうかです。この場合、インスタンスフリートのオプション、プロビジョニングのタイムアウトとブロックインスタンスの採用を検討すると良いでしょう。
その処理にかかる最長時間を、インスタンスフリートで使用するクラスタタイプのうち、もっともロースペックなもので、予め算出しておいて、プロビジョニングタイムアウトを

```
プロビジョニングタイムアウトの時間 = （処理が終わっていないといけない日時 - 処理が開始する日時）の時間 - 処理にかかる時間 - 余裕時間
```

で設定しておきます。

例えば、19:00実行の後続のバッチがあり、15:00にEMRを含む処理があり、その処理が2時間程度かかる、余裕として30分を見ておきたい場合は、

```
プロビジョニングタイムアウトの時間 = （19:00 - 15:00） - 2時間 - 30分 = 1時間30分
```

となります。この1時間30分をプロビジョニングタイムアウトに設定し、プロビジョニングタイムアウト時にオンデマンドに切り替えるようにします。
そして、ブロックインスタンスを （処理時間 + 余裕時間）を超える時間（60分単位）、今回ならば3時間でかけると良いでしょう。

こうすることで、スポット価格がやすい時はスポットで実行され、混雑している時でもギリギリまでスポットの実行をトライして、それでもダメならばオンデマンドで実行する・・・と言う構成を組むことができます。

どうでしょう、ちょっと実践的な設定ではないでしょうか？

なお、21:00のバッチに間に合わなかったとしても処理を継続したいのであれば、ブロックインスタンスは使わないようにしたほうがいいでしょう。
ブロックインスタンスを使ってしまうと、マスターノードが生きていたとしてもエラーで落ちたではなく、正常に終了したと見なされてしまうので、再立ち上げは行われないのです。

## その処理はいつか終わればいいのか？
昔、PS3が発売された時に、世界中にあるユーザーが使っていない時のPS3のリソースを使用して、ガンの研究の計算を行う、といった取り組み（グリッドコンピューティング）がありました。
あれに近いような形で、スポット価格が高い時は控えめのリソース行わせて、安い時には一気にパフォーマンスあげて計算させる・・・ようなことをさせたい場合、On Demand vCPUを使うと良いでしょう。
マスターノードとコアノード1つずつはオンデマンドでおいておき、課金額を低めに設定したスポットインスタンスをいくつか設定すれば良いのです。
こうした使い方は科学計算をはじめとする研究活動で使うようなことが多いのかなと思います。

# インスタンスタイプ構成
前回の記事の中でも記載はしたのですが、インスタンスフリートの構成をとると、そのうちどれが採用されるかはわかりません。
よってそのうちのどれが選ばれても処理が正常終了すること、それは大前提です。
その中で何を選んでいくのかについてです。

## 使うアプリケーションの種類
せっかく上位のインスタンスタイプを使うのであれば、それが上位であるが故のメリットが出せるような構成にするべきでしょう。例えば、 Prestoを使うのであれば、処理速度にメモリ総量が効いてくるので、例えば必要最低スペックがm4.largeであれば、r4.large、m4.xlarge、r4.xlarge、r4.2xlargeといったr系の上位とm系の上位を組み合わせます。
それによって、EMRの処理が早く終わるようであれば、その分EMRの使用コスト削減にも繋がるわけですから。

## 課金上限額
ここに関しては考え方は色々あると思うのですが、、、
私は安定性も一定重視するのであれば、プロビジョニングタイムアウトの設定と、タイムアウト時にオンデマンドに切り替えるオプションはほぼ必須だと考えています。これを使う場合であれば、一番ロースペックなもののオンデマンド価格で設定するのが良いと思います。プロビジョニングタイムアウト時にオンデマンドに切り替わる場合、インスタンスがどれが選ばれるのかはこれまたコストパフォーマンスによるのですが、（経験上）多くの場合はもっともロースペックのものが選ばれます。なので、それと同じ価格を上限に設定する価値があるのではないか（同じ値段でよりハイスペックなものが使えるので）と思います。
逆に、立ち上がらなくても問題ないよということであれば、現実的な範囲でなるべく底値に近いような値を指定しておくのがいいんじゃないかなと思いますよ。

# オンデマンドと戦う
個人的にはここ、結構大事かなと思っています。
課金上限額の欄でも書きましたが、安定性も考慮するならばプロビジョニングタイムアウト + オンデマンドに切り替えるオプションは必要だと思っているのですが、その設定を入れた場合、オンデマンドで立ち上がることがあります。いえ、それは意図通りなんですが・・・
EMRを一定期間に渡ってお使いいただいたことがある方はわかるかもしれませんが、オンデマンドだと長ければ30日以上もクラスタが生き続けているようなケースもあります。それの何が問題かというとですね、インスタンスフリートは起動時にしか考慮されないので、一度オンデマンドで立ち上がってしまうと、スポット価格が安くなったとしてもずっとオンデマンドのまま起動したままになってしまいます。
このままではせっかくインスタンスフリートで安くしようと試みたのに、藻屑の泡ですよね・・・。

それに対する解決策として、私は定期的にEMRクラスターを落とすのが良いのではないかと考えています。溜まっているログとかも一掃できますし。このあたりについては以下でまとめてくれてます。（若干・・・かなり目的と異なっていますが、こういったところも狙って実装検討してもらってます。）

・EMR不使用時のコスト削減のために自動terminate処理を実装してみたhttps://qiita.com/kimi_takasu/items/02959482f3f2a233f900

もちろん、一気に落としてしまうとその間機能が使えなくなってしまうので、代替手段が確保されていることを確認しつつ少しずつ落としていくことが求められます。最初にメインの方を落として、立ち上がったら、今度は冗長系の方を落とす、とか。
これにより、オンデマンドで立ち上がったとしても、再びインスタンスフリートの世界にひきずりこむことができるわけです。できる節約はキリキリとしていきます。

# おわりに
EMRをスポットインスタンスを活用しつつ安定的に稼働させることを目標に、全3回に渡って執筆して参りました。
正直私はスポットインスタンスの入札価格の安定しなささ、乱高下に困っています。同じように、私以外に困っている方も大勢いるでしょう。
私は今から2ヶ月弱前にEMRを触り始めたばかりの若輩者ですので、玄人の諸先輩方からすると一言物申したいこともあるかと思います。ぜひ！ぜひ！コメントをいただけると、そしてもっとこうした方がいいよというアドバイスをいただけると幸いです・・・。
この記事を起点にして、誰かの何かが解決してくれることを祈っています。

（願わくば私の。）

# 参考文献
・新機能 - Amazon EMRインスタンスフリート（公式）
https://aws.amazon.com/jp/blogs/news/new-amazon-emr-instance-fleets/