Webアプリケーションのパフォーマンス改善は、ユーザー体験やビジネス成果に直結する重要なテーマです。しかし、「どこから手を付ければよいか分からない」「改善の流れがイメージしづらい」と感じる方も多いのではないでしょうか。
本記事では、私がこれまで何度かWebアプリケーションのパフォーマンス改善に取り組んできた経験をもとに、改善の流れやよくある改善のパターンを紹介します。
これからパフォーマンス改善に初めて取り組む方や、基本的な進め方・考え方を整理したいWebエンジニアの方に向けて、実践的なヒントをお伝えできれば幸いです!
パフォーマンス改善はやみくもに施策を打つのではなく、現状把握から目標設定、計測、改善案の検討・実施まで、段階的に進めることが重要です。特に「計測」が大事で、現状を正しく把握しないまま改善を進めると効果が見えなかったり、的外れな対応になってしまうこともあります。
ここでは、パフォーマンス改善の基本的な進め方を紹介します。
1. 目標を決める
パフォーマンス改善を始める前に、改善の目的を整理します。ユーザー体験の向上、インフラコストの削減、特定ページの高速化など、パフォーマンスを改善する目的によって目標の立て方が変わります。
目的に応じて「何をどれだけ改善したいのか」という目標を明確にします。たとえば、サーバーのレスポンスタイムやLCP(Largest Contentful Paint)などの指標を使います。また、指標のどの値(例:平均値、p75、p90など)を計測・目標とするかも決めておく必要があります。目標値は、アプリケーションの状況やプロジェクトの期間・リソースに応じて現実的なものにしましょう。
2. 現状を計測・可視化する
目標を決めたら、現状のパフォーマンスを計測します。Datadogなどのサーバー監視ツールや、Lighthouseなどのパフォーマンス計測ツールを使い、どのリクエストや処理がボトルネックになっているかを把握します。
特定のページやAPIの改善を目指していても、別の重いページやリクエストが全体のパフォーマンスやサーバーリソースに影響を与えている場合があります。全体を俯瞰して、他の重い処理が影響していないかも考慮しましょう。
3. 改善案の検討と実施
計測結果をもとに、どの部分をどのように改善できそうかを洗い出します。効果が大きく、工数が少ないものから着手するのが基本ですが、「どれだけ改善できそうか」「どのくらいの工数でできるか」「他への影響はないか」なども考慮して優先順位をつけます。
改善案が決まったら1つずつ実施していき、都度計測して効果を確認します。必要に応じて目標値や方針を見直し、改善サイクルを繰り返すことが大切です。改善方法はアプリケーションや状況によって異なりますが、改善パターンは次章で紹介します。
パフォーマンスの悪い処理をどのように改善するかは処理の内容によりますが、改善方法にはよくあるパターンがいくつかあります。ここではその中のいくつかのパターンを紹介します。
不要な処理を削除する
パフォーマンスの悪い処理がそもそも不要な処理である場合は、その処理を削除することで改善できます。適切に開発していれば不要な処理が残ることは少ないと思いますが、意外と不要な処理が残っている場合があります。特に、大規模なアプリケーションでは不要な処理の消し忘れが残っていたりします。
実際に私が体験した例を挙げると、ある Web アプリケーションで GraphQL でデータを取得してフロントエンドでそれを使用するページがあったのですが、Fragment に現在では使われていないフィールドが残り続けていた、ということがありました。ページにアクセスするたびに、バックエンドではそのフィールドのために DB でクエリを実行していたため、これにより不要なクエリ実行が毎日約1500万回実行されていることが判明しました
(当時、クエリごとの実行回数を確認した際に不自然に多いクエリがあり気づくことができました。Fragment Colocation の導入により未然に防ぐなど対策もしていきたいです)
処理を軽くする
パフォーマンスの悪い処理に対して、SQLやアルゴリズムに改善の余地がないか検討してみましょう。処理の方法を変更することで、処理時間を短縮や負荷を減らすことができます。
Webアプリケーションでよくある例として、N+1問題などがあります。SQL関連だと他にも適切なインデックスを使用したクエリに修正することで速度が改善できます。私も過去にインデックスを追加してクエリを改善したことがあるのですが、改善前は最大で5秒程度かかっていたクエリが、変更後はほぼ毎回10ミリ秒以内で完了するようになりました。
キャッシュする
パフォーマンスの悪い処理を毎回行う代わりに、事前に処理したり、一定時間に一度だけ処理しておき、それ以外ではキャッシュした値を利用することで、改善できます。例えば Qiita だと、 Markdown で書かれた記事を HTML に変換して表示していますが、 記事ページにアクセスするたびに Markdown から HTML に変換しているのではなく、記事作成時や更新時に HTML を生成して DB に保存しておくことで、ページにアクセスするときは DB から HTML を取り出すだけで済むようになっています。
キャッシュの方法もいろいろあります。DB だけでなく、Redis などのインメモリキャッシュ、ブラウザのキャッシュ、CDN など様々です。処理に応じて適切なキャッシュ方法を選びましょう。注意点としてはキャッシュに保存する際には対象となるパフォーマンスの悪い処理を行わないといけないので、できるだけ処理を軽くしてからその上でキャッシュするなど工夫した方がいい場合などもあります。
フレームワークや言語、インフラを見直す
これまでのパターンに当てはまらない場合、つまりパフォーマンスの悪い処理を毎回行わないといけない場合もあります。そんな場合は使用しているフレームワークやプログラミング言語をアップデートしたり、別のものに変更することで改善される場合があります。例えば Ruby では バージョンを上げて YJIT を有効化することでパフォーマンスが大幅に改善された事例がいくつも挙がっています。
他にも、インフラを見直すことで改善できる場合もあります。例えば AWS の EC2 はインスタンスタイプを変更することで処理速度が向上する場合があります。最近話題の Graviton 系のインスタンスタイプに変更することでパフォーマンス改善だけでなくコストも削減できる場合もあります。
フレームワークや言語、インフラの移行は難易度が高く工数も多いですが、それに見合った効果が期待できる可能性も秘めているので、検討する価値があると思います。
パフォーマンス改善は一度で終わるものではなく、継続的な計測と改善のサイクルが大切です。小さな改善でも積み重ねることで、ユーザー体験やビジネス成果に大きなインパクトをもたらします。
ぜひご自身の現場でも、まずは現状の計測から一歩踏み出してみてください。
Views: 0