LoginSignup
10
7

More than 3 years have passed since last update.

PumaやSidekiqでメモリが肥大する問題の対処法

Last updated at Posted at 2020-05-07

RailsアプリケーションでPumaを使ったり、非同期処理のためにSidekiqを使うことはよくあると思います。
アプリケーションを長期運用しているとPumaやSidekiqのメモリ使用量が肥大しOOM Killerにプロセスを殺されたり。なんてことがよく起きます。

原因

メモリ使用量が肥大化する原因の一つとして、Rubyのメモリ管理とmallocの仕様(スレッド単位メモリアリーナ)によりメモリの断片化が発生していることが挙げられます。

メモリの断片化であって、メモリリークしているわけではありません。

解決策1. Puma Worker Killerを使う

Puma Worker KillerというGemがあります。
PumaのWorkerプロセスが設定したメモリを超えた時に自動でそのプロセスを殺して安全に再起動することでメモリの肥大を防ぎます。
根本的な解決ではありませんが、環境をいじれない人にとってや有効かもしれません。
ただPumaのみの解決であってSidekiqの解決にはなりません。

解決策2. メモリアリーナの最大数を変更する

MALLOC_ARENA_MAX環境変数でメモリアリーナの最大数を設定することによってメモリの断片化が改善できます。
MALLOC_ARENA_MAX=2が最適値と言われています。
ちなみにHerokuではMALLOC_ARENA_MAX=2がデフォルトになっているようです。

ただこちらもトレードオフとしてレスポンスタイムが悪化するという実験結果もあります。
https://devcenter.heroku.com/articles/testing-cedar-14-memory-use

解決策3. jemallocを使う

個人的にはこちらの方法をおすすめします。

アロケーターはmallocからjemallocに変更することで解決できる可能性があります。
jemallocもスレッド単位アリーナを実装していますが、mallocで起きる断片化を回避する設計となっています。

Rubyの再ビルドが必要になるので既存のアプリケーションに導入する場合はしっかり検証してください。

手順

jemallocのインストール

sudo yum install jemalloc-devel

rbenvでrubyをビルド

RUBY_CONFIGURE_OPTS=--with-jemalloc rbenv install X.X.X

導入されているか確認

irbで確認します

$ irb
irb(main):002:0> RbConfig::CONFIG['MAINLIBS']
> "-lz -lpthread -lrt -lrt -ljemalloc -lgmp -ldl -lcrypt -lm"

ljemallocが入っていればOK

参考

10
7
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
7