Railsアプリケーションのwheneverタスク起動でspringがメモリ食いまくってサーバ死亡する


主旨

よろしければどなたか教えてください。

問題

railsアプリケーションを運用しているサーバがメモリ不足で死ぬことがある。
私はrails初心者なので、原因というか障害の成り立ちがよく分からずヤバイ。
springというのもよく分かってない。

主な環境

rbenv local で ruby 2.4.2を使用。
rails5.1.4を使用。
unicorn を使用。
whenever を使用。
30分ごとにTwitterに投稿、TwitterAPIを叩ける限り叩く、ちょい時間かかるタスクをwheneverで登録。
Twitterへのつぶやきの内容を編集するviewも用意し、使用している。
以下、railsアプリケーションのルートディレクトリは「/rails_root」とする。

症状

rbenv exec bundle exec unicorn_rails -c config/unicorn.rb -D -E production起動後、htopで見るとrails関係のプロセスはこれだけ(のはず)。

30分ごとのwheneverタスクが起動すると、こういうのが追加される。

wheneverタスクが終了しても、これだけは残存している。

時間を経るごとに、spring appの部分が徐々に増えていって、MEM%4.Xぐらいのプロセスがたくさんになって、数日のうちにサーバが死亡してしまう。

また、spring appを放置して数日過ごしていると、

  • wheneverタスクは動くがviewが503になってしまう
  • viewは使えるが、wheneverタスクがたくさん詰まってメモリ食いまくってサーバ死亡

のいずれかのパターンに陥る。

対策1

なので30分ごとのタスクとかぶらないタイミングで1時間ごとに、以下のようなcronジョブでunicornを再起動するようにしている。

cron_job
cd /rails_root
hg pull
hg update -C tip
rbenv exec rake assets:precompile RAILS_ENV=production
bundle exec whenever --update-crontab RAILS_ENV=production
spring stop
kill -9 `cat /rails_root/tmp/pids/unicorn.pid`
rbenv exec bundle exec unicorn_rails -c config/unicorn.rb -D -E production

肝心なのはspring stopのところで、これによりメモリ食いまくりプロセスが全滅する。
これで事なきを得ているような気がするが、こんな運用はそもそもおかしいと思うし、みんなやってないと思う。
どうしてこうなるのか、どうするべきなのかなどをご存知の方がいらっしゃいましたら、ぜひ教えていただきたいです。

対策2

先述の対策1ではうまくいかなかったので、アプリケーションからspringを削除してみた。

こちらの削除方法を用いた。
http://ruby-rails.hatenadiary.com/entry/20141026/1414289421#spring-removal

bin/spring binstub --remove --all
Gemfile から gem 'spring'をコメントアウト。
rbenv exec bundle install

これでwheneverタスク実行時にspringプロセスは出なくなった。
しかしspringはrailsコマンド実行を高速化する良い機能であるという。
そういったものを止める、というネガティヴな解決方法は遺憾だが、動かなくなるよりはマシなので、より良い方法を見つけるまでは、これで様子を見たい。

心当たり

whenever --update-crontabするとrails runnerとかcrontabに書きこむが、railsコマンドに関連づいているサーバソフトがunicornではないからこうなってるんじゃないかという気がする。
単にrails sを実行すると、pumaというサーバソフトが起動する。unicornではない。
この辺のしくみがよく分からない。

予後

springを削除したら、当然ながらプロセスにspringが出現しなくなり、viewの表示、wheneverによるcronタスク共に安定した。
めでたし。