Web制作、Web開発の歩き方

バックエンドのスタンダード:Laravel入門

■第14話:パフォーマンス最適化とスケーリング

(最終更新日:2024.08.31)

フレームワークのイメージ
この記事は7分で読めます!
(絵が小さい場合はスマホを横に)

「高速で安定なサイトを構築しよう!」

第14回では、Laravelアプリケーションのパフォーマンス最適化とスケーリングに焦点を当てる。 現代のWebアプリケーションでは、迅速なレスポンスと高い信頼性が求められている。 これを実現するためには、キャッシュの効果的な利用、データベースクエリの最適化、リソースの効率的な管理が不可欠だ。 また、トラフィック増加時にも安定した動作を保つためのスケーリング技術についても学ぶ。 これにより、堅牢でスケーラブルなアプリケーションを構築できるようになる。


1.パフォーマンスチューニングの基本

パフォーマンスチューニングの基本では、Laravelアプリケーションの速度と効率を向上させるための基本的なテクニックを紹介する。 以下のような内容を含む。

1.1 キャッシュの活用
ここで言うキャッシュは、ルートキャッシュ、設定キャッシュ、ビューキャッシュの3つになる。

ルートキャッシュは、ルート情報をキャッシュすることで、アプリケーションの起動時にルートファイルを解析する時間を短縮する。 これにより、特に大規模なアプリケーションでのパフォーマンスが向上する。

設定キャッシュは、 設定ファイルをキャッシュすることで、環境設定の読み込み時間を短縮し、リクエストの処理速度を改善する。

ビューキャッシュは、 ビューを事前にコンパイルしてキャッシュすることで、テンプレートのレンダリング時間を削減する。

1.2 データベースクエリの最適化
ここでいう最適化は、N+1クエリ問題の回避、インデックスの適用、クエリビルダの使用の3つになる。

N+1クエリ問題の回避は、リレーションデータの取得時に発生するN+1クエリ問題を、 Eloquentの「with」メソッドを使用して事前に関連データをロードすることで解消できる。

インデックスの適用は、データベースのテーブルに適切なインデックスを設定することで、クエリの実行速度を向上させる。

クエリビルダの使用は、Eloquent ORMの代わりに、必要に応じてクエリビルダを使用し、より軽量なクエリを実行する。

1.3 オートローダの最適化
composer dump-autoload -oコマンドを使用して、クラスマップを生成する。 これにより、Composerのオートローダを最適化し、クラスの読み込み時間を短縮する。

1.4 アセットの圧縮と最適化
JavaScriptやCSSファイルをミニファイ(無駄な空白やコメントを除去して圧縮)することで、リソースの読み込みを高速化する。

1.5 ジョブキューの使用
時間のかかる処理(メール送信やデータ処理など)をジョブキューに移動し、 非同期的にユーザーに素早いレスポンスを返すことで、アプリケーションのレスポンス性能を向上する。

これらの基本的なチューニング方法を駆使することで、 Laravelアプリケーションのパフォーマンスを大幅に改善し、 ユーザーに快適な操作体験を提供することができる。

2.データベースとクエリの最適化

データベースとクエリの最適化では、Laravelアプリケーションのデータベースクエリを効率化し、 全体のパフォーマンスを向上させるための具体的な手法を紹介する。以下に詳しく説明する。

2.1 N+1クエリ問題の回避
N+1クエリ問題は、Eloquentでリレーションデータを取得する際に頻発する。 例えば、親テーブルからデータを取得する際に、子テーブルのデータを個別にN回クエリしてしまい、無駄なクエリが大量に発生する。

これを回避するためには、Eloquentのwithメソッドを使用して、リレーションデータを事前に一括でロードすることで、無駄なクエリを削減できる。 これにより、必要なクエリ数が大幅に減少し、パフォーマンスが向上する。

N+1するコード(上)、N+1しないコード(下)

2.2 クエリキャッシュの利用
同じクエリを頻繁に実行する場合、クエリ結果をキャッシュすることで、データベースへのアクセスを減らし、レスポンス速度を向上できる。 Laravelでは、rememberメソッドを使用して簡単にクエリ結果をキャッシュできる。

rememberメソッドによるキャッシュの適用

2.3 インデックスの適用
データベースのテーブルにインデックスを設定することで、検索やフィルタリングのクエリが高速化される。 特に、大量のデータを扱うテーブルでは、適切なインデックス設定が重要だ。 そして、インデックスを追加するには、 マイグレーションファイルで、 indexやuniqueなどのメソッドを使用して、インデックスを追加する。 下記では、usersテーブルに対してemailカラムをインデックスに追加している。

インデックスの追加

2.4 クエリビルダの使用
軽量なクエリを実行したい場合、Eloquentを使わずクエリビルダを使用することで、余分な処理を省き高速化することができる。 特に複雑なクエリや集計処理を行う際に効果的だ。下記では、usersテーブルのactiveユーザーのユーザ名とEmailを取得している。

クエリビルダの使用

2.5 データベースの接続管理
アプリケーションがデータベースに頻繁にアクセスする場合、接続プーリングや接続の再利用を行うことで、 接続のオーバーヘッドを減らし、効率的なデータベース操作が可能になる。

2.6 スロークエリの監視と最適化
MySQLなどのデータベースでは、スロークエリログを有効にして、実行に時間がかかるクエリを特定し、 それらを最適化することで、全体のパフォーマンスを改善できる。下記では1秒以上かかっているクエリを記録し、 それを分析、調査、クエリの改善を行うことで、パフォーマンスの改善を図ることができる。

クエリビルダの使用

2.7 データベースの分割とシャーディング
特に大規模なアプリケーションでは、データベースを複数のサーバーに分割することで、 負荷を分散させ、クエリのパフォーマンスを向上させることが重要である。 分割としては、シャーディングを使い、各クエリの対象データ量を減らすことで、スケーラビリティとパフォーマンスを高められる。 例えば、150万人のユーザーを50万人ずつ3つのサーバーに分割するといった方法になる。

これらの手法を組み合わせることで、 Laravelアプリケーションのデータベースアクセスのパフォーマンスを最大限に引き出し、 効率的なクエリ処理を実現できる。

3.フロントエンドの最適化

フロントエンドの最適化では、Laravelアプリケーションでのフロントエンド部分において、 ユーザー体験を向上させるための具体的なパフォーマンス改善手法が紹介する。

3.1 アセットのミニファイと結合
CSSやJavaScriptファイルをミニファイ(不要なスペースやコメントを削除)することで、ファイルサイズを縮小し、 読み込み速度を向上させる。Laravel Mixなどのツールを使用して、これを簡単に行うことができる。 例えば「npm run production」コマンドを実行すると、Laravel Mixはアセットをミニファイし、 publicディレクトリに最適化されたファイルを出力する。 また、複数のCSSやJavaScriptファイルを1つのファイルに結合することで、 HTTPリクエストの回数を減らし、ページの読み込み時間を短縮できる。

CSSの結合

3.2 ブラウザキャッシュの活用
静的なアセット(CSS、JavaScript、画像など)に対してブラウザキャッシュを適用することで、 ユーザーが再度同じページを訪れた際の読み込み時間を大幅に短縮できる。 Laravelでは、versioning機能を利用して、アセットにバージョンを付け、キャッシュの制御ができる。 mix()ヘルパーは、ファイルの変更時にキャッシュを自動的に更新する。

CSSのブラウザキャッシュの設定

3.3 画像の最適化
画像ファイルを圧縮し、ファイルサイズを小さくすることで、ページの読み込み速度を向上させる。 ツールとしては、Laravelのパッケージ(spatie/laravel-image-optimizerなど)を利用することができる。 また、適切なフォーマットを使用することも効果的である。 WebPなどの最新の画像フォーマットを使用することで、画質を保ちながら、ファイルサイズを削減できる。

3.4 遅延読み込み(Lazy Loading)
ページ全体の読み込みを高速化するために、画像や非表示の要素を必要なときにのみ読み込む「遅延読み込み」を使用できる。 これにより、初期読み込み時間を短縮し、ユーザー体験が向上する。 HTMLのloading="lazy"属性を利用することで、画像が画面に表示される直前にのみ読み込まれるようになる。

HTMLのlazy設定

3.5 コンテンツ配信ネットワーク(CDN)の使用
静的アセットをコンテンツ配信ネットワーク(CDN)にホスティングすることで、世界中のユーザーに対して高速でコンテンツを提供できる。 CDNは、リクエストを最寄りのサーバーに転送し、読み込み時間を短縮する。

3.6 JavaScriptの非同期・遅延読み込み
JavaScriptファイルを非同期に読み込むことで、ページのレンダリングがブロックされるのを防ぎ、初期表示を高速化する。 ページの主要コンテンツが読み込まれた後に、必要なJavaScriptを実行することで、ユーザー体験を向上させることができる。

非同期読込(上)と遅延読込(下)

3.7 クリティカルCSSのインライン化
初期表示に必要な最小限のCSSをインラインでページに含めることで、ブラウザがスタイルをすぐに適用できる。 ページのレンダリングを高速化させられる。その後、残りのCSSは非同期で読み込む手法を取る。

3.8 フロントエンドフレームワークの効率的な使用
ReactやVue.jsなどのモダンなフロントエンドフレームワークを使用する場合、 コード分割やダイナミックインポートを活用して、必要な部分のみを動的に読み込むことで、初期ロードを軽量化できる。

3.9 HTTP/2やWebPUSHの利用
HTTP/2プロトコルを有効にすることで、複数のリソースを並行して効率的にダウンロードでき、全体的なページロード時間が短縮できる。 また、WebPUSHを用いることで、静的アセットの事前ロードを行い、ユーザーが必要とする前にリソースをダウンロードし、レスポンス速度を向上させる。

これらのフロントエンド最適化技術を組み合わせることで、Laravelアプリケーションのユーザーエクスペリエンスを向上させ、 ページのパフォーマンスを最大化できる。

4.スケーリング戦略とデプロイメント

スケーリング戦略とデプロイメントでは、Laravelアプリケーションを効率的にスケールさせ、 デプロイメントを行うためのベストプラクティスと具体的な手法が紹介する。

4.1 スケーリングの基本概念
スケーリングとは、アプリケーションが多くのリクエストを効率的に処理できるようにするために、 システムのリソース(CPU、メモリ、ディスク、ネットワークなど)を拡張することを指す。 垂直スケーリングとは、単一のサーバーのリソース(CPU、メモリ、ディスク)を増強して、処理能力を向上させる手法だ。 シンプルだが、物理的な限界がある。 一方、水平スケーリングは、複数のサーバーを追加して、システム全体の処理能力を向上させる手法だ。 ロードバランサーを使用して、トラフィックを分散させることで、システム全体のスケーラビリティを高める。

4.2 ロードバランシング
ロードバランサーは、複数のサーバー間でリクエストを均等に分配し、単一のサーバーに負荷が集中しないようにする。 これにより、アプリケーションの可用性が向上し、障害時のリスクが軽減される。 ロードバランサーの設定としては、NGINXやAWS Elastic Load Balancer(ELB)などのツールを利用して、負荷分散の設定を行う。 セッションの持続性やSSL終端など、各種オプションを活用することも可能だ。

4.3 キャッシュの最適化
データベースへの負荷を減らすために、RedisやMemcachedを使用してキャッシュを設定する。 頻繁にアクセスされるデータをキャッシュすることで、レスポンス時間が短縮され、システム全体のパフォーマンスが向上する。 下記のコードでは、ユーザー情報をキャッシュし、指定された秒数だけ保存する。

キャッシュの利用

4.4 セッションとキューのスケーリング
Redisなどの分散キャッシュを使用してセッション管理を行うことで、 セッションデータを共有し、複数サーバー間で一貫性を保つことができる。 また、Laravelのキューワーカーをスケールアウトすることで、バックグラウンドジョブの処理能力を向上させる。 これは、メール送信や通知処理など、大量のバックグラウンド処理を必要とするシステムで特に有効になる。 キューワーカーをデーモンモードで実行(php artisan queue:work --daemon)することで、キュージョブを効率的に処理できる。

4.5 デプロイメント戦略
継続的インテグレーション/継続的デリバリー(CI/CD)を導入することで、 自動化されたテスト、ビルド、デプロイメントを実現し、信頼性の高いリリースを可能にする。 GitLab CI、GitHub Actions、Jenkinsなどを利用する。 また、新しいバージョンのアプリケーションをデプロイする際に、 既存のバージョンを維持しつつ、新しいバージョンにトラフィックを切り替えることで、ダウンタイムを最小限に抑える(ブルーグリーンデプロイメント)。 一方、一度に一部のサーバーに新しいコードをデプロイし、 問題がないことを確認した後に、残りのサーバーに展開していく方法もある。これにより、リスクを分散しながらデプロイを進められる(ローリングデプロイメント)。

4.6 オートスケーリング
AWS EC2 Auto ScalingやGoogle Cloud Auto Scalingを使用して、トラフィックの増減に応じて自動的にサーバーを増減させることが可能だ。 これにより、需要に応じたリソースの供給が可能となり、コスト効率の高いスケーリングを実現できる。

4.7 コンテナとマイクロサービス
Dockerなどのコンテナ技術を利用して、アプリケーションを軽量なコンテナにパッケージングし、ポータブルでスケーラブルな環境を構築する。 Kubernetesなどのオーケストレーションツールを使って、コンテナの管理とスケーリングを行う。

4.8 モニタリングとアラート
パフォーマンスモニタリングツール(New Relic、Datadog、Prometheusなど)を導入して、システムの状態をリアルタイムで監視する。 これにより、潜在的な問題を早期に発見し、迅速に対応することができる。 監視ツールと連携して、異常が発生した際にアラートを受け取るように設定する。 これにより、迅速な対応が可能となり、ダウンタイムを最小限に抑えることができる。

これらのスケーリング戦略とデプロイメント手法を適切に組み合わせることで、 Laravelアプリケーションを効率的にスケールさせ、安定したパフォーマンスを維持することができる。

5.まとめ

今回は、Laravelアプリケーションのパフォーマンス最適化とスケーリングの手法について解説した。 パフォーマンスチューニングの基本から、データベースとクエリの最適化、キャッシュの活用、セッション管理、 ファイルシステムの最適化などを紹介し、さらに、ロードバランシングやオートスケーリング、デプロイメント戦略についても説明した。 これらは、システムの効率的なスケーリングと安定運用のためのベストプラクティスを提供する。 ぜひ、活用してみよう。

▼参考図書、サイト

 「改定2版 速習Laravel」 山田祥寛 WINGSプロジェクト
 「1週間で基礎から学ぶLaravel入門」 Minatomi