1
Help us understand the problem. What are the problem?

posted at

ElasticBeanstalkで動かしているRailsプロジェクトにpuma_worker_killerを導入する

起きた問題

ElasticBeanstalkで動かしているRailsプロジェクトのメモリ使用率が高止まりしていました。
プロセスを見てみるとPumaが主な要因でした。
Image from Gyazo

メモリを解放するために、インスタンスの自動入れ替えも検討しましたが、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の修正

Gemfile
group :production do
  gem 'puma', '5.6.4'
  gem 'puma_worker_killer' #追加
end
$ bundle install

2. config/puma.rbに設定の追加

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再起動

Image from Gyazo

config.rolling_restart_frequency によるWorker再起動

Image from Gyazo

CloudWatchによるメモリ使用率のグラフ

Image from Gyazo

ハマったポイント

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を利用する方針で落ち着きました。

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
1
Help us understand the problem. What are the problem?