Sidekiqのワーカープロセスが増殖してメモリを食い殺す
現在開発を進めていたアプリで、スクレイピングをするためにワーカーに処理を投げるということを行なっていました。その際にSidekiqを使用していたのですが、Sidekiqのワーカープロセスが増殖してサーバーのメモリを食い殺す。という自体が起きてしまい、エラーが頻発するようになってしまったのでその原因を探ってみました。
当初の段階で怪しいと思ったのはSidekiqのconfig/initializers/sidekiq.rb
で設定ファイルに不備があるかconfig/unicorn/production.rb
でUnicornの起動時にRedisとコネクション結ばせている設定がおかしいかの部分ではないかと見込みを付けてみました。
元の設定はこんな感じ
config/initializers/sidekiq.rb
Sidekiq.configure_server do |config| config.redis = { url: ENV['REDIS_URL'], namespace: "sidekiq_#{Rails.env}" } end Sidekiq.configure_client do |config| config.redis = { url: ENV['REDIS_URL'], namespace: "sidekiq_#{Rails.env}" } end
config/unicorn/production.rb
* * * after_fork do |server, worker| Signal.trap 'TERM' do puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to send QUIT' end defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection # When in Unicorn, this block needs to go in unicorn's `after_fork` callback: Sidekiq.configure_client do |config| config.redis = { :url => ENV["REDIS_URL"] , :namespace => "sidekiq_#{Rails.env}"} end end
んで、調査を進めて行った所あまり、参考に出来そうな記事を見つけられず。MRIのバグやら,Sidekiqのメモリリークだなんやらという話がでてくる。解決出来なそうで不安になる。
Sidekiq not deallocating memory after workers have finished
これも問題は問題だが、今回の状況とはちょっと異なる気がする。よくわからなくなって来たのでSidekiqのソースコードを読み始める。
途中、可愛いメソッド見つけてなごんだ。こんなメソッドも動くんだー。
とふと気がついて、Capistranoでのデプロイ時になんかおかしいことが起こってるのではないかと主行ったって調べた所、見事Sidekiqのpidファイルを見つけられずにプロセスを終了させずに新たにプロセスを生成していたことを発見。
バグは、capistranoのsidekiqのpidを指定する部分でフルパスを渡していたせいでした。
config/deploy/production.rb
set :sidekiq_pid, "#{current_path}/tmp/pids/sidekiq.pid"
変更後
config/deploy/production.rb
set :sidekiq_pid, "tmp/pids/sidekiq.pid"
これで、しっかりとSidekiqの再起動時にプロセスがkillされるようになったはずなのでメモリを異常にくうことは無くなったはず。Capistranoがkillできなかった場合に止まってくれなかったこと、それに気付かなかったこと。そしてpidファイルのパス指定が賢くなかったことが重なった悲劇でした。ずっと悩んでいたのですがようやく解決。
にしてもSidekiqのメソッド可愛いですね。