TL; DR
- YJITをDocker/Kubernetesでで有効にするには
RUBY_YJIT_ENABLE=1
orRUBYOPT=--yjit
- YJITはデフォルトで256MBのメモリ領域を確保するため、全体のメモリ消費量が上がる
- Docker/Kubernetesでメモリ量を制御したい場合、
RUBYOPT=--yjit-exec-mem-size=128
のようにメモリ確保量を変更すればよい
Ruby 3.1から使えるYJIT
Ruby on Railsで動くアプリケーションでRubyのMJITが効果的でないことは色んなところで書かれていて、Ruby 3.1から実験的に導入されたShopify製のYJITでは対照的にRailsでのパフォーマンス改善が見込めるという期待があります。
ただしこのYJIT、動かすときには(JITなのでそりゃそうですが)デフォルトで256MiBのメモリを確保しようとします。Kubernetesのように細かいサービスを水平に並べる仕組みを採用する場合、メモリ消費量がある程度重なると"ちりつも"でかなりリソースを圧迫することにも繋がります。
困ったこと
とあるRailsアプリケーションで、以下のようなspecを書いていたのですが、Rubyを3.1に上げてYJITを有効にしただけだと起動後数分でOOMKillerが走ってPodの再起動が散見されるようになりました。
resources: limits: cpu: "1" memory: 512Mi requests: cpu: 800m memory: 256Mi
解決策
Ruby-jp Slackの皆様のお陰で(主に@ko1さん、ありがとうございました)、YJITではデフォルトで256MiBのメモリを確保する点、それからこれをいじるには起動オプション--yjit-exec-mem-size
を指定すれば良い点がわかりました。
RubyのDockerイメージではRUBY_YJIT_ENABLE
とRUBYOPT
が使えるため、DockerfileまたはKubernetes YAMLにはRUBY_YJIT_ENABLE=1
、RUBYOPT=--yjit-exec-mem-size=128
と言った形でENVの指定を入れてあげれば良いということがわかりました。これはDocker Composeでも同じですね。
完全に当時はスルーしてましたが、@mameさんと@ko1さんが書かれたRuby 3.1リリースブログにも起動時のメモリ確保の件は書かれていました。一次情報大事。
今日は短いですがこのへんで。