起きた問題
ElasticBeanstalkで動かしているRailsプロジェクトのメモリ使用率が高止まりしていました。
プロセスを見てみるとPumaが主な要因でした。
メモリを解放するために、インスタンスの自動入れ替えも検討しましたが、ElasticIPの自動付与問題の課題があり、今回はpuma_worker_killer
というgemを使用してみることにしました。
puma_worker_killerの公式ページ
https://github.com/zombocom/puma_worker_killer
前提
- ElasticBeanstalk環境 (Ruby 2.7 running on 64bit Amazon Linux 2/3.4.7)
- EC2インスタンス数:1台 (ElasticIP付き)
- Puma worker数:2
手順
1.Gemfileの修正
group :production do
gem 'puma', '5.6.4'
gem 'puma_worker_killer' #追加
end
$ bundle install
2. config/puma.rbに設定の追加
if ENV.fetch("RAILS_ENV") == "production"
# ElasticBeanstalkのpumaconf.rbのデフォルト設定
directory '/var/app/current'
threads 8, 32
workers %x(grep -c processor /proc/cpuinfo)
bind 'unix:///var/run/puma/my_app.sock'
stdout_redirect '/var/log/puma/puma.log', '/var/log/puma/puma.log', true
# PumaWorkerKiller設定
before_fork do
require 'puma_worker_killer'
PumaWorkerKiller.config do |config|
config.ram = 4096 # EC2インスタンスのメモリ量(MB)
config.frequency = 5 * 60 # 何秒ごとに現在のメモリ使用量を確認するか(5分ごと)
config.percent_usage = 0.80 # Pumaがメモリを何%使ったら再起動するか(アラート発砲が90%、他のプロセスもメモリを喰うことを考えて80%にする)
config.rolling_restart_frequency = 24 * 60 * 60 # 上記の設定とは別に、1日に1回は再起動する
config.reaper_status_logs = true # ログ出力(デバッグ用)
end
PumaWorkerKiller.start
end
end
3. Procfileの準備
web: mkdir -p /var/app/current/tmp/pids && bundle exec puma -C /var/app/current/config/puma.rb
効果確認
EB環境でpuma.logを確認した結果です
cat /var/log/puma/puma.log | grep "PumaWorkerKiller"
config.percent_usage によるWorker再起動
config.rolling_restart_frequency によるWorker再起動
CloudWatchによるメモリ使用率のグラフ
ハマったポイント
1.EB環境でPumaWorkerKillerが起動しない
デフォルトのElasticBeanstalk環境だとconfig/puma.rb
の設定を見ずに、/opt/elasticbeanstalk/config/private/pumaconf.rb
の設定を利用してPumaを起動しているようでした。
そのため、config/puma.rb
に設定を記載しているのにEB環境ではPumaWorkerKillerが起動せずに、ローカルでのテストでは起動するという現象が発生しました。
ルートディレクトリにProcfile
を作成し、config/puma.rb
を使用してPumaを起動させることで解決しています。
併せて、/opt/elasticbeanstalk/config/private/pumaconf.rb
にあったデフォルト設定を、/config/puma.rb
にも記載しています。
Procfileについて
https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/ruby-platform-procfile.html
2.pumaconf.rbを.ebextentionsで修正するも、PumaWorkerKillerを読み込めない
/opt/elasticbeanstalk/config/private/pumaconf.rb
の設定を利用すると知った最初は、.ebextentions
を利用してpumaconf.rb
にPumaWorkerKillerの設定を追記しようとしましたが、以下のエラーが出て上手くいきませんでした。
/opt/rubies/ruby-2.7.6/lib/ruby/site_ruby/2.7.0/rubygems/core_ext/kernel_require.rb:85:in `require': cannot load such file -- puma_worker_killer (LoadError)
puma/puma.log:[8772] WARNING hook before_fork failed with exception (NameError) uninitialized constant #<Class:#<Puma::DSL:0x0000000001df7130>>::PumaWorkerKiller
解決の糸口が見つからず、最終的にはProcfile
を使用して、config/puma.rb
を利用する方針で落ち着きました。