Heroku Dyno再起動時の振る舞い

3,533 views

Published on

Dynoの自動再起動についてHerokuサポートとやりとりした記録です。

  • Be the first to comment

Heroku Dyno再起動時の振る舞い

  1. 1. 小西俊司 株式会社FLECT
  2. 2.  Heroku上でPlay1アプリケーションを運用中 ◦ Playframework 1.2.5 ◦ WebDyno複数、WorkerDyno必要時のみ起動  まれにHerokuのDynoが自動再起動する際に以下のロ グが出力されることがある ◦ Playのソースを見るとPlayがシャットダウンした後にHttpリ クエストを受けた場合に発生するっぽい。 ◦ 頻度は2週に1回程度でそれほど多くはない  これはこの問題についてHerokuのサポートチームと やりとりした詳細の記録です。 play.exceptions.UnexpectedException: Application is not started
  3. 3.  https://devcenter.heroku.com/articles/dynos  Dynoは少なくとも1日に1度自動的に再起動す る ◦ ログを監視する限り24時間前後で再起動(Cycling)が発 生している ◦ 定期的な再起動以外にアプリやプラットフォームの異常 を検出した場合にも再起動する  再起動時にはまず対象DynoにSIGTERMが送られ る  SIGTERM送信後10秒間応答が無い場合はSIGKILL が送られる  再起動時の新しいDynoは旧Dynoシャットダウン 後に起動される
  4. 4.  SIGTREMを受けてPlayはshutdownHookで終了処理を行うがこ の時にはNettyに対してはなんの処理も行われない。  このためPlayのリクエストハンドラが終了した後でもNettyは生 きており新しいリクエストを受け付ける。 (しかし、この場合は 問答無用で503が返る)  シャットダウン後にタイムラグがあった場合、その間にHeroku のルーターからリクエストが来ると503が返ってしまう。 通常はAppシャットダウン後、 直ちにVMが終了するが、まれに 終了までに数秒かかる場合があ る
  5. 5.  HerokuのルーターはSIGTERMを送ったDynoに対してリ クエストを送信することがある。(エラー発生頻度からの 推測だが、常にそうなる訳ではなくControllerとのレー ス状態によって発生することがあるということかも?) ◦ そのリクエストがソケット接続に失敗した場合は別のDynoにリ トライされる(問題なし) ◦ 503を受け取った場合はそのままクライアントに返される(アウ ト)
  6. 6.  Playframework ◦ Playはアプリのシャットダウン前にNettyのソケットをクローズす るべき。 ◦ アプリケーション開発者がonStopなどのフックからNettyを直接 参照する方法はない。  Heroku ◦ HerokuはSIGTERMを送信したDynoに対してリクエストを送信す るべきではない。 ◦ Herokuはアプリのシャットダウン時にはまずソケットがクローズ されることを期待している、と言えるがそれはフレームワークの 実装依存。 ◦ ルータの動作はアプリケーション開発者からは制御不能な領域。 Play本体を直すことは(技術的には)可能だが、Heroku側で対 応 する方がベター。 (Play以外のフレームワークでも同じ問題があるかもしれない し。) しかしどの道すぐには難しそう。。。。(--
  7. 7.  Heroku labsで公開されているβ機能 ◦ https://devcenter.heroku.com/articles/labs-preboot  Prebootを適用するとDyno再起動時の動作が ◦ ルータ一時停止 -> 旧Dyno停止 ->新Dyno起動 -> ルータ再開 から ◦ 新Dyno起動 -> ルータスイッチ -> 旧Dyno停止 となる これで万事解決か???
  8. 8.  対象となるDyno ◦ WebDynoのみ ◦ 少なくとも2台以上のWebDynoが起動していなければな らない。  いつ適用されるのか? 開発者が ◦ 「git push」した場合 ◦ 「heroku config:set」した場合 ◦ 「heroku restart」した場合 自動再起動時は適用対象外。。。(-- Prebootは1年以上前からlabs にあるがずっとそこからでてこ ない。 デフォルトにした場合、一時的な インスタンス数がかなり増えそう なのでずっとlabsのままかも。。。
  9. 9.  今のところ根本的な解決方法はなさそう。。。(- -  現行サービスの特徴 ◦ ユーザーはほぼ日本人。 ◦ このため日本時間の明け方頃が最もアクセストラフィッ クが低い。  もしもHerokuの自動再起動がかかる時間を深夜 にコントロールすることができれば、それはエ ラーの発生率低減に繋がるはず。 ◦ もともとの発生率自体がそれほど高くないがやはり可能 な限りエラーの可能性は低くしたい。
  10. 10.  https://github.com/gregburek/heroku- buildpack-toolbelt  HerokuToolbeltをDynoにインストールする buildpack。  これを利用することでHerokuのスケジューラから herokuコマンドを発行できるようになる。 ◦ 名前に「toolbelt」とあるがherokuコマンド以外の余計なモ ノ(foreman, gitなど)は入っていないっぽい。 ◦ ドキュメントでは「HEROKU_TOOLBELT_API_EMAIL」 「HEROKU_TOOLBELT_API_PASSWORD」の二つの環境変数 を設定とあるが、「HEROKU_API_KEY」一つだけの設定でも OK ◦ Buildpack-multiで既存のDynoに組み込むこともできるが、 スケジューラでのDyno制御専用に新しいアプリを建てる方が 楽。
  11. 11.  Daily at 18:30 (3:30 JST) ◦ vendor/heroku-toolbelt/bin/heroku restart web.1 -a xxx  Daily at 19:00 (4:00 JST) ◦ vendor/heroku-toolbelt/bin/heroku restart web.2 -a xxx 複数のWebDynoを時間をずらして再起動させる。  Prebootの組み合わせも有効。(というか組み合わせないと元の問題解決 にはならない)  この設定によって昼間の再起動が絶対に発生しないということではな い。 ◦ 例えばベースとなるハードウェアの障害などを検出した場合は再起動が発生す る。  日時の再起動が必ず24時間以上のサイクルで起きるのかどうかは要検 証。 ◦ 例えば4:00 AMにrestartをスケジュールした場合に、3:55 AMに自動再起動がか かる可能性があるのではないか。 ◦ Herokuサポートからは最初は「ありえる」という回答だったが、別の人は「発生 しない」という回答だった。(質問のニュアンスがどの程度正確に伝わっているか イマイチ自信が無いので、どこまで厳密な回答なのかが判断できなんだ。。。(--) ◦ 数日テストしているが今のところ発生したことはない。
  12. 12.  以下のどっちかをHeroku側で対応してほしい。 ◦ SIGTERMを送ったDynoにはリクエストを送信しない ◦ Prebootを自動再起動時にも適用する  もちろんHerokuサポートにも要望として伝えて はいる。。。が、どの程度ニュアンスが(以下略)

×