DiscourseにおけるRuby 3.2のYJITの本番環境での運用について

Tan Guo Xiang
May 10, 2023 • 4 min read

Discourseでは、ShopifyのRuby & Railsインフラチームが本番環境への導入準備が整ったと宣言して以来、YJITの採用に積極的に取り組んでまいりました。ローカル環境でのベンチマークが有望な結果を示したことを受け、2023年5月上旬に選定したクラスター上でRuby 3.2のYJITを有効化した状態で本番のRailsアプリケーションを稼働させ始めました。その後、実際のパフォーマンスの計測に一定の時間を費やしました。観測されたポジティブな結果を皆さんと共有できることを嬉しく思います。これらの知見に基づき、現在はホスティング全体でYJITを有効化しており、セルフホスト利用者も同様にオプトインできるようになっています。

DiscourseのYJIT実験

ローカル環境でのDiscourseベンチマークは有望な結果を示していましたが、ホスト型インスタンス全体でYJITを有効化する判断を下す前に、本番環境でこれらの結果を検証したいと考えていました。そのために、本番環境でYJIT実験を実施しました。2つの本番クラスターを選択し、それぞれのクラスターをYJITを有効化したインスタンスを実行するグループとそうでないグループの2つに分けました。デプロイのオーケストレーションにHashicorp Nomadを使用しているため、この分割は容易に実現できました。既存のNomadジョブ内でRUBY_YJIT_ENABLE環境変数を持つタスクの追加グループを指定し、ロードバランサーにラウンドロビンアルゴリズムを使用してグループ間でリクエストを割り振らせるだけで済みました。

その後、discourse-prometheusプラグインに新しいhttp_application_duration_seconds Prometheusメトリクスを導入しました。このメトリクスはリクエスト中にRubyコードの実行に費やされた時間を計測するものです。このメトリクスは、リクエストの合計時間からSQLクエリとRedisコマンドの実行に費やされた時間を差し引くことで算出されます。これにより、SQLクエリやRedisコマンドの実行によるノイズを排除した上で、YJITがRubyアプリケーションコードの実行に与える影響を切り分けることができました。

これらの変更により、以下のようなグラフを用いて本番ワークロードに対するYJITの影響を容易に可視化・計測できるようになりました。

ログイン済みユーザーへのトピックリスト表示においてRubyコードの実行に費やされた中央値時間

匿名ユーザーへのトピックリスト表示においてRubyコードの実行に費やされた中央値時間

24時間の実験実施後、結果を集計しました。以下は、それぞれ無料ティアおよびビジネスティアのお客様を対象とした無料クラスターとビジネスクラスターで確認された結果です。

無料クラスターでは、YJITを有効化することで、トピックリストおよび個別トピックの閲覧におけるRubyコード実行の中央値時間が15.8%から19.6%の範囲で短縮されました。

リクエストタイプ YJITなし (ms) YJITあり (ms) 差異 (%)
Latest (HTML) 127 106 16.5%
Latest (JSON) 54.9 45.3 17.5%
Topic (HTML) 104 86.3 17.0%
Topic (JSON) 58.6 49 16.4%

リクエストタイプ YJITなし (ms) YJITあり (ms) 差異 (%)
Latest (HTML) 96.6 80.5 16.7%
Latest (JSON) 48 38.6 19.6%
Topic (HTML) 51.8 43.7 15.8%
Topic (JSON) 34.5 28.8 16.5%

メモリに関しては、6つのワーカープロセスを持つUnicorn Webサーバーを実行するDockerコンテナで、メモリ使用量が約18%増加することが確認されました。

コンテナのメモリ使用量

ビジネスクラスターでも同様のスピードアップが確認され、トピックリストおよび個別トピックの閲覧におけるリクエスト時間の中央値が12.9%から19.3%の範囲で短縮されました。メモリ使用量の増加はビジネスクラスターでも無料クラスターと非常に近い結果となり、10のワーカープロセスを持つUnicorn Webサーバーを実行するDockerコンテナで約16.7%の増加が確認されました。

観測されたポジティブな結果を受け、ホスティングプラットフォーム全体でYJITを有効化する自信を得ました。唯一のトレードオフはメモリ使用量の増加ですが、サーバーには十分なメモリが確保されているため、これは懸念事項にはなりません。

Discourseホスト型ユーザーの方へ

Discourseのホスト型ユーザーの方には、現在すべてのホスト型インスタンスがYJITを有効化した状態で稼働していることをお知らせします。これにより、応答時間が短縮され、ユーザーのブラウジング体験が向上します。

Discourseセルフホスト利用者の方へ

Discourseをセルフホストされている方は、コンテナ定義ファイルにenable-ruby-yjit.template.ymlを追加することでYJITを有効化できます。例:

templates:
  - 'templates/enable-ruby-yjit.yml'

メモリ使用量の増加を考慮し、セルフホスト型インスタンスではYJITをデフォルトで有効化しないことを選択しています。YJITを有効化するセルフホスト利用者は、サーバーが追加のメモリ要件に対応できることを確認するために、メモリ使用量を監視してください。

まとめ

Discourseの本番環境でRuby 3.2のYJITを有効化したことにより、ユーザーに対して大幅なパフォーマンス向上をもたらすことができました。これがDiscourseコミュニティに与えるポジティブな影響に期待しています。最後に、Rubyコアチーム、ShopifyのYJITチーム、そしてYJITに何らかの形で貢献してくださったすべての方々に感謝の意を表します。

原文はこちら:


Good Loopでは、Discourseのセルフホスティングを安価で提供しています。開発元であるCDCK社の協力のもと、公式ブログ記事の翻訳・公開など、日本での普及にも努めています。

詳しくはこちら: Discourseの導入・運用支援・コンサルティング – Good Loop