Ruby 3.3 + YJITにアップデートしてパフォーマンスが大幅に向上しました
はじめに
先日はRubyKaigiお疲れ様でした!
早速ポークたまごおにぎりとさんぴん茶が恋しくなってるBackendエンジニアのrinceです。
弊社サービス「マイベスト」では、5月上旬にRuby 3.3.1 + YJITにアップデートしてパフォーマンスが大幅に向上したので、今回はその詳細についてご紹介したいと思います。
Ruby 3.3のYJITについて
まず、Ruby 3.2から3.3でYJITに関していくつか改善が行われました。
高速化やメモリ使用量の削減に加えて、Code GCがデフォルトで無効になったり、RubyVM::YJIT.enable
というメソッドが追加されたりしています。
特に、RubyVM::YJIT.enable
については、Ruby 3.2の時にはYJITを環境変数 RUBY_YJIT_ENABLE
で有効化する必要があったのですが、3.3からはRubyのコード内でこのメソッドを実行するだけでYJITを有効化できるようになりました。
弊社でも、このタイミングで以下のようにRailsのイニシャライザ内でYJITを有効化するようにしました。
if defined? RubyVM::YJIT.enable
Rails.application.config.after_initialize do
RubyVM::YJIT.enable
end
end
ちなみにRailsでも7.2からはデフォルトで上記の方法でYJITが有効化されます。
Ruby 3.3のYJITの改善点についてさらに詳しく知りたい方は、k0kubunさんの以下の記事が詳しいのでぜひ参考にしてみてください。
また、3.2から3.3にかけてどのように高速化したかについては、k0kubunさんがRubyKaigiでも発表していてとても興味深かったです。
結果
ここからはRuby 3.3.1 + YJITにアップデートした結果について紹介します。
前提
前提として、今回アップデートしたアプリケーションのRubyやRailsのバージョンは以下となっています。
- アップデート前のRubyバージョンは3.2.2で、YJITは既に導入済み
- アップデート後のRubyバージョンは3.3.1
- Railsのバージョンは7.1.3
-
--yjit-exec-mem-size
や--yjit-call-threshold
はデフォルト設定のまま
レスポンスタイムの変化
以下はアップデート前後でのユーザー向けのAPIリクエスト全体のレスポンスタイムの50パーセンタイル(p50)と95パーセンタイル(p95)のグラフです。
青線がアップデート後、グレーがアップデート前で、1週間前の値と比較しています。
(※Rubyアップデートの2日前にMySQLのバージョンをアップデートしたので、その影響が含まれないよう2日間で比較しています)
p50では、平均が5.9msから4.9msとなり、16.9%高速化されました。
p95では、平均が963.6msから672.5msとなり、30.2%高速化されました。
p50でも16.9%と大きく改善されましたが、キャッシュの効かないリクエストが多くなるp95では30.2%と大幅に改善されました。
メモリ使用量の変化
メモリ使用量については、アップデートの前後で特に大きな変化はありませんでした。
サービスによってはメモリ使用量が上がった事例もあったようなので、少し懸念して事前に負荷テストも行い問題ないことを検証していましたが、実際に本番リリースでも何事もなくてよかったです。
まとめ
本記事では、マイベストのRubyのバージョンを3.3.1 + YJITにアップデートした際のパフォーマンスの変化について紹介しました。
ユーザー向けのAPIリクエスト全体のレスポンスタイムで約16〜30%の大幅な高速化が見られました。
Ruby 3.2 + YJITにアップデートした際にも感じましたが、バージョンを上げるごとにアプリケーションのパフォーマンスが向上して、Rubyコミッターの方々に感謝です。
最後に、RubyKaigiまでの1ヶ月間、弊社のエンジニアで『mybest BlogKaigi 2024』というテックブログ連載企画を実施していたので、もしご興味を持っていただけた方がいたらぜひこちらも見ていただけると嬉しいです!
参考記事
株式会社マイベストのテックブログです! 採用情報はこちら > notion.so/mybestcom/mybest-information-for-Engineers-8beadd9c91ef4dc2b21171d48a4b0c49
Discussion