ビール大好きですが、3回に1回は年齢確認をされる26歳エンジニアの村上(pipopotamasu (pipopotamasu) · GitHub)です。
今回はリクエストからレンダリング完了までの時間を減らした取り組みについて書こうと思います。
きっかけ
メドピアではメインプロダクトをRuby on Railsで開発しています。 Railsで開発を始めてから2年半、すくすくとアプリケーションが成長してきています。 しかし成長していくにつれ問題が出てくるのが世の常、以下のような問題が生じてきました。
「ページ読み込みが遅い...」
Webアプリケーション開発者は開発環境で1日に何十回とページ読み込みをさせると思いますが、Railsの成長と共にそれがめちゃくちゃ遅くなってきたのです。
環境
メドピアのフロントエンド環境はassets pipeline(browserify-railsを用いてビルドしている)で管理している部分と、Webapckerで管理している部分があります。 今回の取り組みは、JavaScriptをassets pipelineからWebpackerへ移行している過渡期に行いました。
問題は何か?
さて、ページの読み込みがめちゃくちゃ遅いという問題にぶちあたりましたが、これだと問題が大き過ぎるのでもうちょっと細分化してみましょう。 以下はリクエストからページレンダリング完了までの流れになります(超ざっくりです)。
①~⑤まで確認してみたところ、②と④、⑤に時間がかかっていることがわかりました。
まずdev toolの計測を見てみましょう。
青色が待機時間、サーバーから応答が返るまでの待ち時間です。最初のHTML取得で結構時間がかかっていることがわかります。 ピンク色はブロック時間、ネットワーク接続の待ち行列で費やした時間を表しています。
最初のHTML取得までの時間、つまり②の時間が遅いことについては、開発環境であるためRailsのconfig.cache_classes
をfalseにしていてコードのキャッシュをさせないようにしているので、遅いのはある程度仕方がないのですが、それにしても遅い...。サーバ側でのViewのレンダリングにかなりの時間を費やしています。
# config/environments/development.rb config.cache_classes = false
またdev toolの計測を見てみると、CSSやJavaScriptといったアセットを取得しに行く時間、つまり④、⑤も異常に遅いです、全リソースを読み込むのに15秒もかかってるorz。そもそも読み込もうとしているJavaScriptが多すぎますね。
原因は何か?
②が遅い原因
アプリケーションログを遡っていくと、あることに時間を費やしているのがわかりました、browserifyのビルドです。
JavaScriptに何かしらの変更を加えた時に、browserifyのビルドが走っていてそれが遅く感じる原因のようです。
どうやらbrowserifyはWebpackなどと違い、デフォルトで差分ビルドができず(watchifyというプラグインが必要)、JavaScriptを変更した後にエントリーポイントで読み込むファイルを全ビルドしていたためにかなり遅くなっていました。 読み込んでいるJavaScriptの種類にもよりますが、約4~6秒ほどかかっていました。
④と⑤が遅い原因
読み込もうとしているJavaScriptが多すぎて、ブラウザの同時接続数(Chromeは6)をオーバーしているためです。前述したdev toolのピンク色がブロック時間、つまり接続待ちを表しています。
そもそも何故こんなにも読み込むJavaScriptが多いのでしょうか?
どうやらdevelopment環境のデフォルトで、assets pipelineで本来一纏めにされるJavaScriptがデバック用にバラバラで読み込まれる設定がされているようです。
# config/environments/development.rb config.assets.debug = true
これにより読み込むJavaScriptが多くなりすぎて、接続待ちに時間が多く費やされていました。
対策
browserifyのビルドが遅い問題
watchifyを導入して、差分ビルドをさせるようにするという案もありましたが、最終的にWebpackに置き換えるという形にしました。 これについては別に記事を書いているのでよろしければご覧ください。
最終的にbrowserifyの全ビルドから、Webpackの差分ビルドに置き換えたことにより、 4~6秒 → 1.5秒 に短縮することができました。
読み込むJavaScriptが多すぎる問題
デバックモードもそれはそれでデバックしたい時には便利なので、単純にconfigの値をfalseにするだけだと切り替えが面倒です。
# config/environments/development.rb config.assets.debug = false # デバッグしたい時にtrueに書き換えてappサーバを再起動する必要がある
しかしconfig.assets.debug
がfalseの時、Railsのjavascript_include_tag
ヘルパーのdebugオプションをtrueにすることで、デバックモードに切り替えることができます。
このオプションを利用して、debugしたい時だけURLに特定のパラメータを付与するとdebugモードに切り替わるヘルパーを作成しました。
def javascript_include_tag_with_debug_option(js, options = {}) javascript_include_tag js, options.merge(debug: params[:js_debug].present?) end
このヘルパーを利用することで、通常時のリクエストはdebugモードはOffですが、以下のように特定のパラメータを付与するとOnにできるようになりました。
https://hostname.jp/articles?js_debug=on
終わりに
今回は開発環境の話でしたが、本番環境でもリソース取得時間の改善の余地がまだまだあります。 「サイトの読み込み時間を爆速にする」ことに興味がある方は是非一度メドピアに遊びに来てください。
また9月12日にメドピアでRailsの技術的負債をテーマにした「MedBeer」というイベントを開催します。
負債の予防・返却に興味がある人、ビールが飲みたい人は是非参加してください。
(☝︎ ՞ਊ ՞)☝︎是非読者になってください
メドピアでは一緒に働く仲間を募集しています。 ご応募をお待ちしております!
■募集ポジションはこちら
https://medpeer.co.jp/recruit/entry/
■開発環境はこちら