この記事は
- SidekiqをDocker環境で安定稼働させるためのメモです
困っていたこと
- Sidekiqは便利なワーカサーバなのですが、長時間起動しているとメモリリークしていく特性があります
- sidekiq-worker-killerなど、無理やり再起動をかますライブラリも存在するのですが、Dockerとの相性が悪くコンテナが終了してしまうので、今っぽい環境ではうまく使えません
原因
- そもそもメモリの断片化が原因らしく、Sidekiqの問題というかRuby自体の問題のようです
- pumaも放っておくとどんどんリークするから、puma-worker-killerは必須ですもんね・・・
jemalloc
- これを解決できるのがjemallocです
- これは普通のmalloc(glibc malloc)と同じメモリ管理をする役割のライブラリですが、独自の断片化対策がされているんだそうです
- Rubyがjemallocを利用するように対応すれば、エンドレスのメモリリークを止めることができます
対応方法
- Dockerファイルに下記を追記するだけです(debianベースのコンテナの場合)
Dockerfile
RUN apt-get install -y libjemalloc2
ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2
- ちなみにApple Siliconの開発機上のdockerで動きを見る場合は下記になります(パスが変わる)
Dockerfile
ENV LD_PRELOAD=/usr/lib/aarch64-linux-gnu/libjemalloc.so.2
効果
- datadogのグラフを見ていると、それまで右肩上がりに上がり続けていたメモリ使用量が横ばいになりました!
- 数ヶ月見ていますが、特に動きが不安定になって落ちるなどもなく、性能も変化なく安定稼働しています
LD_PRELOAD
- 上記の
LD_PRELOAD
という環境変数が入ると、このコンテナで動いているプログラムほぼ全てにおいて、jemallocが利用されるようにすげ変わることになります - つまりRuby以外のプログラムが想定外の動きをする可能性を完全に否定はできないということです
信頼性について
- Sidekiqを作っている人たちもjemallocを推しているそうなので、そういう意味ではそこの相性問題はそうそう起こらないのかなーと思います
- 一方で、上記LD_PRELOADの方式は、若干トリッキーなので注意ではあります
- Ruby界隈ではかなり検索にひっかかり、比較的に普及した方法なので、ことさらにリスクが高いわけではありませんが・・・
- あるべき論でいうとrubyをビルドする時にjemaloocをリンクするような方式が正しいとは思います
- fullstaq-rubyという、ちゃんとjemallocをリンクしてビルドして配布されているバイナリも存在しているようです
- この手のはメンテがどこまで続くのが不安なので個人的には避けています・・・(RubyEEとかあったよねー懐)
終わりに
- もうメモリで悩まなくてもええんや!