Web アプリケーションのスケーリング: 基本的な手順

公開: 2022-09-13

ビジネス用のアプリケーションを作成するだけでは十分ではなく、最適化する必要があります。 効果的な方法は、スケーリングすることです。 この記事では、コードの最適化、アーキテクチャの最適化、およびスケーラブルな Web アプリケーションの一般的な構築方法について学習します。

最適化中

Gearheart は、次の質問を自問することをお勧めします。

  • データベースクエリは最適ですか (EXPLAIN 分析、インデックスの使用)?
  • データは正しく保存されていますか (SQL と NoSQL)?
  • キャッシュは使用されていますか?
  • FS またはデータベースへの不要な要求はありませんか?
  • データ処理アルゴリズムは最適ですか?
  • 環境設定は最適ですか: Apache/Nginx、MySQL/PostgreSQL、PHP/Python?

これらの質問のそれぞれは別の記事でカバーされる可能性があるため、この記事の枠組みの中でそれらを詳細に検討することは明らかに過剰です. アプリケーションのスケーリングを開始する前に、その作業を可能な限り最適化することが非常に望ましいことを理解することが重要です。実際、スケーリングがまったく必要ない可能性もあります。

スケーリング

すでにアプリケーションを最適化しているが、それでも負荷を処理できないとします。 この場合の明らかな解決策は、アプリケーションを複数のホストに分散して、使用可能なリソースを増やしてアプリケーションの全体的なパフォーマンスを向上させることです。 このアプローチは、正式にはアプリケーションの「スケーリング」と呼ばれます。 より正確には、スケーラビリティとは、使用可能なリソースの量を増やすことによってパフォーマンスを向上させるシステムの能力です。

スケーラビリティには、垂直方向と水平方向の 2 種類があります。 垂直方向のスケーラビリティとは、1 つのノード (ホスト) 内にリソース (CPU、メモリ、ディスク) を追加することで、アプリケーションのパフォーマンスを向上させることを意味します。 水平スケーリングは分散アプリケーションでは一般的であり、別のノードを追加してアプリケーションのパフォーマンスを向上させることを意味します。

最も簡単な方法は、単純なハードウェア (プロセッサ、メモリ、ディスク) のアップグレード、つまり垂直方向のスケーリングであることは明らかです。 さらに、このアプローチでは、アプリケーションを変更する必要はありません。 ただし、垂直方向のスケーリングはすぐに限界に達し、その後、開発者と管理者はアプリケーションの水平方向のスケーリングに切り替えるしかありません。

アプリケーション アーキテクチャ

ほとんどの Web アプリケーションはアプリオリに分散されています。そのアーキテクチャは、Web サーバー、ビジネス ロジック (アプリケーション)、データ (データベース、静的) の少なくとも 3 つの層に分割できるためです。

これらの各レイヤーはスケーリングできます。 したがって、システムにアプリケーションとデータベースが同じホストにある場合、最初のステップは、それらを異なるホストに分離することです。

ボトルネック

システムのスケーリングに進むと、最初に行うべきことは、どのレイヤーが「ボトルネック」であるか、つまり、システムの残りの部分よりも遅いかを判断することです。 まず、top (htop) などの簡単なユーティリティを使用して CPU/メモリの消費を評価し、df、iostat を使用してディスクの消費を評価できます。 ただし、(AB または JMeter を使用して) バトル ロード エミュレーションを備えた別のホストを提供し、xdebug、oprofile などのユーティリティを使用してアプリケーションをプロファイリングできることが望ましいです。 pgFouine のようなユーティリティを使用して、狭いデータベース クエリを識別することができます (もちろん、バトル サーバーのログに基づいて行う方がよいでしょう)。

通常、アプリケーションのアーキテクチャによって異なりますが、一般的に、ボトルネックの可能性が最も高いのはデータベースとコードです。 アプリケーションが大量のユーザー データを処理する場合、ボトルネックは静的ストレージである可能性があります。

データベースのスケーリング

前述のように、最新のアプリケーションのボトルネックは多くの場合、データベースです。 それに関する問題は通常、パフォーマンスと大量のデータを保存する必要性という 2 つのクラスに分けられます。

データベースを複数のホストに分割することで、データベースの負荷を軽減できます。 それらの間の同期には深刻な問題がありますが、同期または非同期のレプリケーションを使用してマスター/スレーブ方式を実装することで解決できます。 PostgreSQL の場合、同期レプリケーションには Slony-I を使用し、非同期レプリケーションには PgPool-II または WAL (9.0) を使用できます。 読み取り要求と書き込み要求を分割し、スレーブ間の負荷を分散するという問題を解決するために、特別なデータベース アクセス レイヤー (PgPool-II) を構成できます。

リレーショナル データベースの場合に大量のデータを格納するという懸念は、パーティショニング (PostgreSQL では「パーティショニング」) によって、または Hadoop DFS などの分散データベースにデータベースを展開することによって解決できます。

両方のソリューションについては、PostgreSQL の構成に関する優れた本で読むことができます。

1.しかし、大量のデータを格納するための最良のソリューションはシャーディングです。これは、ほとんどの NoSQL データベース (MongoDB など) に固有の利点です。

2.さらに、クエリの解析/最適化、データ構造の整合性のチェックなどのオーバーヘッドがないため、一般的にNoSQLデータベースは他のSQLデータベースよりも高速に動作します。リレーショナルデータベースとNoSQLデータベースを比較するトピックも非常に広範であり、価値があります別記事。

3.別に注目に値するのは、JOIN 選択なしで MySQL を使用する Facebook の経験です。 この戦略により、負荷をデータベースからコードに転送しながら、データベースをはるかに簡単にスケーリングできます。コードは、以下で説明するように、データベースよりも簡単にスケーリングできます。

コードのスケーリング

  • コードのスケーリングの複雑さは、ホストがアプリケーションを実行するために必要な共有リソースの数によって異なります。 セッションだけですか、それともキャッシュとファイルを共有する必要がありますか? いずれにせよ、最初に行うことは、同じ環境の複数のホストでアプリケーションのコピーを実行することです。
  • 次に、これらのホスト間の負荷/リクエスト バランシングを設定する必要があります。 TCP (HAProxy)、HTTP (nginx)、または DNS の両方で実行できます。
  • 次のステップは、Gearheart が述べたように、静的ファイル、キャッシュ、および Web アプリケーション セッションを各ホストで利用できるようにすることです。 セッションの場合、ネットワーク上で動作するサーバー (Memcached など) を使用できます。 キャッシュ サーバーとして、同じ Memcached を使用することは理にかなっていますが、もちろん別のホスト上にあります。
  • 静的ファイルは、NFS/CIFS を介して、または分散 FS (HDFS、GlusterFS、Ceph) を使用して、一部の共有ファイル ストレージからマウントできます。

ファイルをデータベース (Mongo GridFS など) に保存することも可能で、それによって可用性とスケーラビリティの問題を解決します (NoSQL データベースのスケーラビリティの問題はシャーディングによって解決されることを考慮してください)。

個別に注目すべきは、複数のホストへの展開の問題です。 ユーザーが「更新」をクリックしても、異なるバージョンのアプリケーションが表示されないようにする方法は? 私の意見では、最も簡単な解決策は、更新されていないホストを構成ロードバランサー (Web サーバー) から除外し、更新が行われるたびに順次オンにすることです。 Cookie または IP によってユーザーを特定のホストにバインドすることもできます。 更新によってデータベースに大幅な変更が必要な場合、最も簡単な方法は、プロジェクトを一時的に閉じることです。