この記事は最初に公式アカウントで公開されました: さらなる AI (power_ai)、注目を歓迎します、プログラミングと AI 乾物は間に合うように配達されます!
何百万ものユーザーをサポートするシステムの設計は困難であり、継続的な改良と継続的な改善が必要な旅です。この章では、単一のユーザーをサポートし、数百万のユーザーにサービスを提供できるようにスケールアップするシステムを構築します。この章を読むと、システム設計面接の質問を解決するのに役立ついくつかのテクニックが得られます。
単一サーバーのセットアップ
千マイルの旅も一歩から始まり、複雑なシステムの構築も同様です。まず簡単なことから始めますが、すべてを 1 つのサーバー上で実行しています。図 1 は、Web アプリケーション、データベース、キャッシュなど、すべてが 1 つのサーバー上で実行される単一サーバー設定の概略図を示しています。
この設定を理解するには、リクエスト フローとトラフィック ソースを調査することが役立ちます。まずリクエスト フローを見てみましょう (図 1-2)。
- ユーザーは、api.mysite.com などのドメイン名を介して Web サイトにアクセスします。通常、ドメイン ネーム システム (DNS) はサードパーティによって提供される有料サービスであり、当社のサーバーではホストされません。
- インターネット プロトコル (IP) アドレスがブラウザまたはモバイル アプリケーションに返されます。この例では、返される IP アドレスは 15.125.23.214 です。
- IP アドレスが取得されると、ハイパーテキスト転送プロトコル (HTTP)[1] リクエストが Web サーバーに直接送信されます。
- Web サーバーは、レンダリング用の HTML ページまたは JSON 応答を返します。
次にトラフィックソースを見てみましょう。Web サーバーへのトラフィックは、Web アプリケーションとモバイル アプリケーションの 2 つのソースから来ます。
- Web アプリケーション: ビジネス ロジック、ストレージなどに一連のサーバー側言語 (Java、Python など) を使用し、プレゼンテーションにクライアント側言語 (HTML および JavaScript) を使用します。
- モバイル アプリ: HTTP プロトコルは、モバイル アプリと Web サーバー間の通信プロトコルです。JavaScript Object Notation (JSON) はその単純さのため、データ転送用の API 応答形式としてよく使用されます。JSON 形式で表示される API 応答の例を次に示します。
GET /users/12 – ID 12 のユーザー オブジェクトを取得します
データベース
ユーザー ベースが拡大するにつれて、1 台のサーバーでは不十分になり、Web サイトとモバイル トラフィック用に 1 台、データベース用に 1 台の複数のサーバーが必要になりました (図 1-3)。Web サイトとモバイル トラフィック (Web 層) をデータベース (データ層) サーバーから分離することで、それぞれを独立して拡張できます。
どのデータベースを使用するか?
従来のリレーショナル データベースまたは非リレーショナル データベースを選択できます。それらがどのように異なるかを見てみましょう。
リレーショナル データベースは、リレーショナル データベース管理システム (RDBMS) または SQL データベースとも呼ばれます。最も人気のあるものは、MySQL、Oracle データベース、PostgreSQL などです。リレーショナル データベースは、テーブルと行を使用してデータを表現し、保存します。SQL を使用して、異なるデータベース テーブル間で結合操作を実行できます。
非リレーショナル データベースは NoSQL データベースとも呼ばれます。一般的なものには、CouchDB、Neo4j、Cassandra、HBase、Amazon DynamoDB などが含まれます [2]。これらのデータベースは、キー/値ストア、グラフ ストア、列ストア、ドキュメント ストアの 4 つのカテゴリに分類されます。非リレーショナル データベースは通常、結合操作をサポートしません。
ほとんどの開発者にとって、リレーショナル データベースは 40 年以上前から存在し、歴史的に優れたパフォーマンスを発揮してきたため、最良の選択です。ただし、リレーショナル データベースが特定のユースケースに適していない場合は、リレーショナル データベースの枠を超えて検討することが重要です。次の場合には、非リレーショナル データベースが正しい選択となる可能性があります。
- アプリケーションには超低遅延が必要です。
- データが構造化されていないか、リレーショナル データがありません。
- データ (JSON、XML、YAML など) をシリアル化および逆シリアル化するだけです。
- 大量のデータを保存する必要があります。
垂直スケーリングと水平スケーリング
「垂直スケーリング」とも呼ばれる垂直スケーリングは、サーバーの処理能力 (CPU、RAM など) を追加するプロセスです。「水平スケーリング」とも呼ばれる水平スケーリングを使用すると、リソース プールにサーバーを追加してスケールアウトできます。
垂直スケーリングは、トラフィックが少ない場合に最適なオプションであり、垂直スケーリングのシンプルさが主な利点です。残念ながら、これにはいくつかの重大な制限もあります。
- 垂直方向のスケーリングには厳しい制限があります。単一サーバーに無制限の CPU とメモリを追加することはできません。
- フェイルオーバーや冗長性を持たない垂直スケーリング。1 つのサーバーがダウンすると、Web サイトやアプリに完全にアクセスできなくなります。
垂直方向のスケーリングには制限があるため、大規模なアプリケーションには水平方向のスケーリングがより理想的です。
以前の設計では、ユーザーは Web サーバーに直接接続していました。Web サーバーがオフラインになると、ユーザーは Web サイトにアクセスできなくなります。また、多くのユーザーが同時に Web サーバーにアクセスし、Web サーバーの負荷制限に達すると、ユーザーは応答が遅い、またはサーバーに接続できないという問題に遭遇することがよくあります。ロード バランサーは、これらの問題を解決する最適なテクノロジーです。
ロードバランサ
ロード バランサーは、受信トラフィックをロード バランシング コレクションで定義された Web サーバーに均等に分散します。図 1-4 は、ロード バランサがどのように動作するかを示しています。
図 1-4 に示すように、ユーザーはロード バランサーのパブリック IP に直接接続します。この設定では、クライアントは Web サーバーに直接アクセスできなくなります。セキュリティを強化するために、サーバー間の通信にはプライベート IP が使用されます。プライベート IP は、インターネット経由ではなく、同じネットワーク上のサーバー間でのみアクセスできる IP アドレスです。ロード バランサーは、プライベート IP を介して Web サーバーと通信します。
図 1-4 では、ロード バランサと 2 番目の Web サーバーを追加すると、フェールオーバーの問題が正常に解決され、Web 層の可用性が向上しました。詳細は以下のとおりです。
- サーバー 1 がオフラインになると、すべてのトラフィックはサーバー 2 にルーティングされます。これにより、Web サイトのダウンタイムが防止されます。新しい正常な Web サーバーをサーバー プールに追加して、負荷のバランスをとることもできます。
- Web サイトのトラフィックが急速に増加し、2 台のサーバーがトラフィックを処理できない場合、ロード バランサーがこれを適切に処理できます。Web サーバー プールにサーバーを追加するだけで、ロード バランサーが自動的にサーバーへのリクエストの送信を開始します。
Web 層は問題ないようですが、データ層はどうなるのでしょうか? 現在の設計にはデータベースが 1 つしかないため、フェイルオーバーと冗長性はサポートされていません。データベース レプリケーションは、これらの問題を解決するための一般的な技術です。見てみましょう。
データベースのレプリケーション
Wikipedia からの引用: 「データベース レプリケーションは、通常、元のデータベース (マスター データベース) とコピー (スレーブ データベース) の間にマスター/スレーブ関係を確立するために、多くのデータベース管理システムで使用できます。」[3]
通常、プライマリ データベースは書き込み操作のみをサポートします。スレーブ データベースはマスター データベースからデータのコピーを取得し、読み取り操作のみをサポートします。挿入、削除、更新などのデータを変更するすべてのコマンドは、プライマリ データベースに送信する必要があります。ほとんどのアプリケーションでは、より高い読み取りと書き込みの比率が必要なため、システム内のスレーブの数は通常、マスターの数よりも多くなります。図 1-5 は、複数のスレーブ データベースを持つマスター データベースを示しています。
データベース レプリケーションの利点:
- パフォーマンスの向上: マスター/スレーブ モデルでは、すべての書き込み操作と更新操作はマスター ノードで実行され、読み取り操作はスレーブ ノード間で分散されます。このモデルでは、より多くのクエリを並行して処理できるため、パフォーマンスが向上します。
- 信頼性: 台風や地震などの自然災害によってデータベース サーバーの 1 つが破壊された場合でも、データは引き続き保存されます。データは複数の場所にレプリケートされるため、データ損失を心配する必要はありません。
- 高可用性: データを別の場所にレプリケートすることで、1 つのデータベースがオフラインになっても、別のデータベース サーバーに保存されているデータにアクセスできるため、Web サイトは引き続き機能します。
前のセクションでは、ロード バランサーがシステムの可用性の向上にどのように役立つかについて説明しました。ここでも同じ質問をします。データベースの 1 つがオフラインになったらどうなるでしょうか? 図 1-5 で説明するアーキテクチャ設計は、この状況に対処します。
- 使用可能なスレーブが 1 つだけでオフラインになる場合、読み取り操作は一時的にマスターに送られます。問題が発見されると、古いスレーブ データベースが新しいスレーブ データベースに置き換えられます。利用可能なスレーブが複数ある場合、読み取り操作は他の正常なスレーブにリダイレクトされます。新しいデータベース サーバーが古いデータベースを置き換えます。
- マスターがオフラインになると、スレーブが新しいマスターに昇格します。すべてのデータベース操作は一時的に新しいプライマリ データベースで実行されます。新しいスレーブ データベースは、データ レプリケーションのために古いデータベースをすぐに置き換えます。運用システムでは、スレーブ内のデータが最新ではない可能性があるため、新しいマスターの昇格はより複雑になります。欠落しているデータは、データ回復スクリプトを実行して更新する必要があります。マルチマスター レプリケーションやリング レプリケーションなど、他のレプリケーション方法も役に立ちますが、これらの設定はより複雑であり、その説明は本書の範囲を超えています。興味のある読者は、リストされた参考文献 [4] [5] を参照してください。
図 1-6 は、ロード バランサとデータベース レプリケーションを追加したシステム設計を示しています。
デザインを見てみましょう:
- ユーザーはロードバランサーの IP アドレスを DNS から取得します。
- ユーザーはこの IP アドレスを使用してロード バランサーに接続します。
- HTTP リクエストはサーバー 1 またはサーバー 2 にルーティングされます。
- Web サーバーはデータベースからユーザー データを読み取ります。
- Web サーバーは、データを変更する操作をメイン データベースにルーティングします。書き込み、更新、削除の操作が含まれます。
- Web レイヤーとデータ レイヤーについてしっかり理解できたので、次はキャッシュ レイヤーを追加し、静的コンテンツ (JavaScript/CSS/画像/ビデオ ファイル) をコンテンツ配信ネットワーク (CDN) に移動することで、読み込み/応答時間を改善します。
キャッシュ
キャッシュは、後続のリクエストをより迅速に処理できるように、高価な応答結果や頻繁にアクセスされるデータをメモリに保存するために使用される一時的な記憶領域です。図 1-6 に示すように、新しい Web ページがロードされるたびに、データをフェッチするために 1 つ以上のデータベース呼び出しが行われます。データベースへの呼び出しを繰り返すと、アプリケーションのパフォーマンスに重大な影響を与える可能性があります。キャッシュを使用すると、この問題を軽減できます。
キャッシュ層
キャッシュ レイヤーは、データベースよりもはるかに高速な一時的なデータ ストレージ レイヤーです。個別のキャッシュ層を設けることには、システム パフォーマンスの向上、データベース ワークロードの軽減、キャッシュ層を個別に拡張できるなどの利点があります。図 1-7 は、可能なキャッシュ サーバーの設定を示しています。
リクエストを受信した後、Web サーバーはまずキャッシュ内に利用可能なレスポンスがあるかどうかを確認します。その場合は、データをクライアントに送り返します。そうでない場合は、データベースにクエリを実行し、応答をキャッシュに保存して、クライアントに送り返します。このキャッシュ戦略は、リードスルー キャッシュと呼ばれます。データのタイプ、サイズ、アクセス パターンに応じて、他のキャッシュ戦略も使用される場合があります。以前の研究では、さまざまなキャッシュ戦略がどのように機能するかを説明しました [6]。ほとんどのキャッシュ サーバーは共通のプログラミング言語用の API を提供しているため、キャッシュ サーバーとの対話は非常に簡単です。次のコード スニペットは、一般的な Memcached API を示しています。
キャッシュの使用に関する考慮事項
キャッシュ システムを使用する際に考慮すべき問題がいくつかあります。
-
キャッシュをいつ使用するかを決定します。データが頻繁に読み取られるが、ほとんど変更されない場合は、キャッシュの使用を検討してください。キャッシュされたデータは揮発性メモリに保存されるため、キャッシュ サーバーは永続的なデータには適していません。たとえば、キャッシュ サーバーが再起動されると、メモリ内のすべてのデータが失われます。したがって、重要なデータは永続的なデータ ストレージに保存する必要があります。
-
有効期限ポリシー。有効期限ポリシーを実装することをお勧めします。キャッシュされたデータの有効期限が切れると、キャッシュから削除されます。有効期限ポリシーがない場合、キャッシュされたデータはメモリに永続的に保存されます。有効期限を短く設定しすぎないことをお勧めします。短く設定すると、システムがデータベースからデータを頻繁に再ロードすることになります。同時に、データが古くならないように、有効期限を長すぎるように設定することはお勧めできません。
-
一貫性: これには、データ ストアとキャッシュの同期を維持することが含まれます。データ ストアとキャッシュに対するデータ変更操作が単一のトランザクション内で行われないため、不整合が発生する可能性があります。複数のリージョンにまたがってスケーリングする場合、データ ストアとキャッシュ間の一貫性を維持することは困難です。詳細については、Facebook が公開した論文「Scaling Memcache at Facebook」を参照してください [7]。
-
障害の軽減: 単一のキャッシュ サーバーは潜在的な単一障害点 (SPOF) を表しており、Wikipedia では次のように定義されています。「単一障害点 (SPOF) はシステムの一部であり、障害が発生するとシステム全体に影響を及ぼします。仕事をやめる」 [8]。したがって、単一障害点を避けるために、異なるデータセンターで複数のキャッシュ サーバーを使用することをお勧めします。もう 1 つの推奨される方法は、必要なメモリを一定の割合でオーバーコミットすることです。これにより、メモリ使用量が増加した場合に備えてバッファが提供されます。
-
エビクション ポリシー: キャッシュがいっぱいになると、キャッシュにアイテムを追加するリクエストによって既存のアイテムが削除される可能性があります。これはキャッシュエビクションとして知られています。最も一般的なキャッシュエビクション戦略は、最も最近使用されていない (LRU) です。さまざまなユースケースに応じて、最も使用頻度の低い (LFU) や先入れ先出し (FIFO) などの他の排除戦略を採用できます。
コンテンツ配信ネットワーク (CDN)
CDN は、静的コンテンツの配信に使用される地理的に分散されたサーバーのネットワークです。CDN サーバーは、画像、ビデオ、CSS、JavaScript ファイルなどの静的コンテンツをキャッシュします。
動的コンテンツ キャッシュは比較的新しい概念であり、本書の範囲外です。リクエスト パス、クエリ文字列、Cookie、リクエスト ヘッダーに基づいて HTML ページのキャッシュを有効にします。詳細については、参考文献 [9] に記載されている記事を参照してください。この本では、CDN を使用して静的コンテンツをキャッシュする方法に焦点を当てています。
CDN が高レベルでどのように機能するかは次のとおりです。ユーザーが Web サイトにアクセスすると、ユーザーに最も近い CDN サーバーが静的コンテンツを配信します。直感的には、ユーザーが CDN サーバーから離れるほど、Web サイトの読み込みが遅くなります。たとえば、CDN サーバーがサンフランシスコにある場合、ロサンゼルスのユーザーはヨーロッパのユーザーよりも早くコンテンツを取得できます。図 1-9 は、CDN によってロード時間がどのように改善されるかを示す良い例です。
図 1-10 は CDN ワークフローを示しています。
- ユーザー A は、画像 URL を使用して image.png を取得しようとします。URL のドメイン名は CDN プロバイダーによって提供されます。次の 2 つの画像 URL は、Amazon および Akamai CDN のサンプル画像 URL を示すために使用されます。
- https://mysite.cloudfront.net/logo.jpg
- https://mysite.akamai.com/image-manager/img/logo.jpg
- CDN サーバーに image.png のキャッシュがない場合、CDN サーバーはソース (Web サーバーまたは Amazon S3 などのオンライン ストレージ) からファイルをリクエストします。
- オリジンは、画像がキャッシュされていた期間を示すオプションの HTTP ヘッダー Time-to-Live (TTL) を含む image.png を CDN サーバーに返します。
- CDN は画像をキャッシュし、ユーザー A に返します。画像は、TTL が期限切れになるまで CDN にキャッシュされます。
- ユーザー B は、同じ画像を取得するリクエストを送信します。
- TTL が期限切れになっていない限り、画像はキャッシュから返されます。
CDN の使用に関する考慮事項
- コスト: CDN はサードパーティのプロバイダーによって運営されており、CDN 内外のデータ転送には料金がかかります。使用頻度が低いリソースの場合、キャッシュによる大きな利点はないため、CDN から移動することを検討する必要があります。
- 適切なキャッシュ有効期限を設定する: 時間に敏感なコンテンツの場合、キャッシュ有効期限を設定することが非常に重要です。キャッシュの有効期限は長すぎても短すぎてもいけません。時間が長すぎると、コンテンツの新鮮さが失われる可能性があります。この時間が短すぎると、配信元サーバーから CDN へのコンテンツの再読み込みが繰り返し行われる可能性があります。
- CDN フォールバック: Web サイト/アプリケーションが CDN 障害をどのように処理するかを検討する必要があります。CDN が一時的に停止した場合、クライアントは問題を検出し、オリジンからリソースを取得できる必要があります。
- ファイルを無効にする: ファイルが期限切れになる前に、次の方法で CDN からファイルを削除できます。
- CDN プロバイダーが提供する API を使用して CDN オブジェクトを無効にします。
- オブジェクトのバージョン管理を使用して、さまざまなバージョンのオブジェクトを提供します。オブジェクトをバージョン管理するには、バージョン番号などのパラメーターを URL に追加します。たとえば、バージョン番号 2 をクエリ文字列 image.png?v=2 に追加します。
図 1-11 は、CDN とキャッシュを追加した後の設計を示しています。
- 静的リソース (JS、CSS、画像など) は Web サーバーによって提供されなくなりました。これらはパフォーマンスを向上させるために CDN から取得されます。
- データをキャッシュすることでデータベースの負荷が軽減されます。
ステートレスなWeb層
今こそ、Web 層を水平方向にスケーリングすることを検討する時期です。これを行うには、状態 (ユーザー セッション データなど) を Web 層の外に移動する必要があります。セッション データをリレーショナル データベースや NoSQL データベースなどの永続ストアに保存することをお勧めします。クラスター内のすべての Web サーバーは、データベースの状態データにアクセスできます。これはステートレス Web 層と呼ばれます。
ステートフルアーキテクチャ
ステートフル サーバーとステートレス サーバーの間には、いくつかの重要な違いがあります。ステートフル サーバーは、あるリクエストから次のリクエストまでのクライアント データ (状態) を記憶します。ステートレス サーバーは状態情報を一切保存しません。
図 1-12 は、ステートフル アーキテクチャの例を示しています。
図 1-12 では、ユーザー A のセッション データとプロフィール写真がサーバー 1 に保存されています。ユーザー A を認証するには、HTTP リクエストをサーバー 1 にルーティングする必要があります。リクエストが他のサーバー、たとえばサーバー 2 に送信された場合、サーバー 2 にはユーザー A のセッション データが含まれていないため、認証は失敗します。同様に、ユーザー B からのすべての HTTP リクエストはサーバー 2 にルーティングされ、ユーザー C からのすべてのリクエストはサーバー 3 に送信される必要があります。
問題は、同じクライアントからのすべてのリクエストを同じサーバーにルーティングする必要があることです。ほとんどのロード バランサーでは、これはスティッキー セッション [10] で実現できますが、オーバーヘッドが追加されます。この方法を使用すると、サーバーの追加または削除がより困難になります。サーバー障害への対処も課題です。
ステートレスなアーキテクチャ
図 1-13 はステートレス アーキテクチャを示しています。
このステートレス アーキテクチャでは、ユーザーの HTTP リクエストを任意の Web サーバーに送信でき、Web サーバーは共有データ ストアから状態データを取得します。状態データは共有データ ストアに保存され、Web サーバーには保持されません。ステートレス システムは、よりシンプルで、より堅牢で、スケーラブルです。
図 1-14 は、ステートレス Web 層を使用した更新された設計を示しています。
図 1-14 では、セッション データを Web 層から移動し、永続データ ストアに保存しました。共有データ ストレージには、リレーショナル データベース、Memcached/Redis、NoSQL などを使用できます。NoSQL データ ストアが選択されたのは、スケーリングが容易であるためです。自動スケーリングとは、トラフィック負荷に基づいて Web サーバーを自動的に追加または削除することを意味します。Web 層の自動スケーリングは、状態データが Web サーバーから削除された後、トラフィック負荷に基づいてサーバーを追加または削除することで簡単に実現できます。
あなたのウェブサイトは急速に成長しており、多数の海外ユーザーを魅了しています。可用性を高め、より広い地理的領域にわたってより良いユーザー エクスペリエンスを提供するには、複数のデータ センターをサポートすることが重要です。
データセンター
図 1-15 は、2 つのデータセンターを使用したセットアップ例を示しています。通常の運用では、ユーザーは地理的位置に基づいて geoDNS 経由で最も近いデータ センターにルーティングされます。トラフィックのx%は米国東部、トラフィックの *(100 - x)%* は米国西部です。geoDNS は、ユーザーの位置に基づいてドメイン名を IP アドレスに解決する DNS サービスです。
データセンターに大規模な障害が発生した場合、すべてのトラフィックが機能しているデータセンターに転送されます。図 1-16 では、データ センター 2 (米国西部) がオフラインで、トラフィックの 100% がデータ センター 1 (米国東部) にルーティングされています。
マルチデータセンターのセットアップを実装するには、いくつかの技術的な課題に対処する必要があります。
- トラフィックのリダイレクト: トラフィックを正しいデータセンターに転送するには、効果的なツールが必要です。ユーザーの場所に応じて、geoDNS を使用してトラフィックを最も近いデータ センターに転送できます。
- データの同期: 異なる地域のユーザーは、異なるローカル データベースまたはキャッシュを使用する場合があります。フェイルオーバー状況では、データが利用できないデータセンターにトラフィックがルーティングされる可能性があります。一般的な戦略は、複数のデータセンター間でデータを複製することです。以前の研究では、Netflix が非同期マルチデータセンター レプリケーションをどのように実現するかを示しました [11]。
- テストと展開: マルチデータセンター設定の場合、Web サイト/アプリケーションをさまざまな場所でテストすることが重要です。すべてのデータセンターでサービスの一貫性を保つには、自動展開ツールが不可欠です [11]。
システムをさらに拡張するには、システムのさまざまなコンポーネントを分離して、それぞれが独立して拡張できるようにする必要があります。メッセージ キューは、この問題を解決するために多くの実際の分散システムで使用される重要な戦略です。
メッセージキュー
メッセージ キューは、メモリに保存される永続的なコンポーネントであり、非同期通信をサポートするために使用されます。これはバッファとして機能し、非同期リクエストをディスパッチします。メッセージ キューの基本的なアーキテクチャは単純です。プロデューサ/パブリッシャーと呼ばれる入力サービスはメッセージを作成し、メッセージ キューにパブリッシュします。コンシューマー/サブスクライバーと呼ばれる他のサービスまたはサーバーはキューに接続し、メッセージによって定義された操作を実行します。モデルを図 1-17 に示します。
分離により、メッセージ キューは、スケーラブルで信頼性の高いアプリケーションを構築するために最適なアーキテクチャになります。メッセージ キューを使用すると、コンシューマがメッセージを処理できないときに、プロデューサはメッセージをキューにポストできます。コンシューマは、プロデューサが利用できない場合でも、キューからメッセージを読み取ることができます。
次の使用例を考えてみましょう。アプリケーションは、トリミング、シャープ化、ぼかしなどを含む写真のカスタマイズをサポートしています。これらのカスタマイズ タスクが完了するまでには時間がかかります。図 1-18 では、Web サーバーが写真処理ジョブをメッセージ キューにポストします。写真処理ワーカーはメッセージ キューからジョブを受け取り、写真のカスタマイズ タスクを非同期に実行します。プロデューサーとコンシューマーは独立して拡張できます。キューのサイズが大きくなった場合、ワーカーを追加して処理時間を短縮できます。ただし、ほとんどの時間キューが空の場合は、ワーカーの数を減らすことができます。
ロギング、メトリクス、自動化
ロギング、メトリクス、自動化のサポートは良い習慣ですが、少数のサーバーで実行されている小規模な Web サイトを扱う場合には必須ではありません。しかし、Web サイトが大企業にサービスを提供する Web サイトに成長した現在、これらのツールへの投資は不可欠です。
ログ: エラー ログの監視は、システム内のエラーや問題を特定するのに役立つため、非常に重要です。サーバーごとのレベルでエラー ログを監視したり、ツールを使用してエラー ログを一元化されたサービスに集約して検索や表示を容易にしたりできます。
メトリクス: さまざまなタイプのメトリクスを収集すると、ビジネスに関する洞察が得られ、システムの健全性を理解するのに役立ちます。以下にいくつかの有用な指標を示します。
- ホストレベルのメトリクス: CPU、メモリ、ディスク I/O など。
- 集計レベルのメトリクス: データベース層全体、キャッシュ層などのパフォーマンス。
- 主要なビジネス指標: 毎日のアクティブ ユーザー、維持率、収益など。
自動化: システムが大規模で複雑になると、生産性を向上させるために自動化ツールを構築または活用する必要があります。継続的インテグレーションは、各コードのコミットを自動的に検証することでチームが問題を早期に検出できるようにするための優れたプラクティスです。さらに、ビルド、テスト、展開プロセスなどを自動化すると、開発者の生産性が大幅に向上します。
メッセージキューとその他のツールを追加する
図 1-19 は、更新された設計を示しています。スペースの制約のため、図には 1 つのデータセンターのみが示されています。
- システムの疎結合性と耐障害性を高めるために、メッセージ キューが設計に組み込まれています。
- ロギング、モニタリング、メトリクス、自動化ツールが含まれます。
データが日々増加するにつれて、データベースの負荷はますます重くなっています。データ層を拡張する時が来ました。
データベース拡張子
データベースのスケーリングには、垂直スケーリングと水平スケーリングという 2 つの主なアプローチがあります。
垂直方向の拡張
垂直スケーリングとも呼ばれるスケーリングは、既存のマシンにパフォーマンス (CPU、RAM、DISK など) を追加することによって行われます。強力なデータベース サーバーがいくつかあります。Amazon Relational Database Service (RDS) [12] によると、24 TB RAM を備えたデータベース サーバーを入手できます。この強力なデータベース サーバーは、大量のデータを保存および処理できます。たとえば、2013 年の stackoverflow.com には月間 1,000 万人を超えるユニーク訪問者がいましたが、マスター データベースは 1 つしかありませんでした [13]。ただし、垂直スケーリングにはいくつかの重大な欠点もあります。
- データベース サーバーに CPU、RAM などを追加できますが、ハードウェアの制限があります。ユーザーの数が多い場合、単一サーバーでは十分ではありません。
- 単一障害点のリスクが増加します。
- 垂直スケーリングの全体的なコストは高くなります。強力なサーバーは高価です。
横展開
シャーディングとも呼ばれ、サーバーを追加する方法です。図 1-20 は、垂直スケーリングと水平スケーリングを比較しています。
シャーディングでは、大規模なデータベースが、シャードと呼ばれる、より管理しやすい小さな部分に分割されます。各シャードは同じスキーマを共有しますが、各シャード上の実際のデータは一意です。
図 1-21 は、シャード データベースの例を示しています。ユーザー データは、ユーザー ID に基づいてデータベース サーバーに割り当てられます。データにアクセスするたびに、ハッシュ関数を使用して対応するシャードが検索されます。この例では、user_id % 4がハッシュ関数として使用されます。結果が 0 の場合は、シャード 0 を使用してデータを保存およびフェッチします。結果が 1 の場合は、シャード 1 を使用します。他のシャードのロジックも同じです。
図 1-22 は、シャード データベースのユーザー テーブルを示しています。
シャーディング戦略を実装する場合、最も重要な要素はシャード キーの選択です。シャード キー (パーティション キーとも呼ばれる) は、データの分散方法を決定する 1 つ以上の列で構成されます。図 1-22 に示すように、「user_id」はシャード キーです。シャード キーを使用すると、データベース クエリを正しいデータベースにルーティングすることで、データを効率的に取得および変更できます。シャード キーを選択する場合、最も重要な基準の 1 つは、データを均等に分散するキーを選択することです。
シャーディングはデータベースを拡張するための優れた手法ですが、完璧なソリューションには程遠いです。これにより、システムに複雑さと新たな課題が生じます。
データの再シャーディング: 1) 急速な増加により、単一シャードがそれ以上のデータを保持できなくなった場合、データを再シャーディングする必要があります。2) 一部のシャードでは、データの分散が不均一であるため、シャードがより早く使い果たされる可能性があります。シャードが使い果たされると、シャーディング機能を更新してデータを移動する必要があります。この問題を解決するために一般的に使用される手法は、第 5 章で説明するコンシステント ハッシュです。
ホットキー問題: スター問題とも呼ばれます。特定のシャードへのアクセスが過剰になると、サーバーに過負荷がかかる可能性があります。ケイティ ペリー、ジャスティン ビーバー、レディー ガガのデータがすべて同じシャードに保存されると想像してください。ソーシャル アプリケーションの場合、シャードは読み取り操作であふれます。この問題を解決するには、各有名人にシャードを割り当てる必要がある場合があります。各シャードでもさらにパーティション分割が必要になる場合があります。
結合と非正規化: データベースが複数のサーバー間でシャード化されると、データベース シャード間で結合操作を実行することが困難になります。一般的な回避策は、データベースを非正規化して、単一のテーブルに対してクエリを実行できるようにすることです。
図 1-23 では、急速に増大するデータ トラフィックをサポートするためにデータベースをシャード化しています。同時に、データベースの負荷を軽減するために、一部の非リレーショナル関数が NoSQL データ ストアに移動されました。こちらの記事では、NoSQL の多くのユースケースを取り上げています [14]。
数百万のユーザーを超えるスケールに対応
システムの拡張は反復的なプロセスです。この章で学んだことを繰り返すことで、大きな成果が得られるかもしれません。数百万のユーザーを超えるには、さらなる最適化と新しい戦略が必要です。たとえば、システムを最適化し、より小さなサービスに分離する必要がある場合があります。この章で学んだすべてのテクニックは、新しい課題に取り組むための優れた基盤となります。この章の締めくくりとして、数百万のユーザーをサポートするためにシステムがどのように拡張されるかを要約します。
- Web層をステートレスに保つ
- あらゆるレベルで冗長性を構築
- 可能な限りデータをキャッシュする
- 複数のデータセンターのサポート
- CDN で静的リソースをホストする
- シャーディングによるデータレイヤーのスケーリング
- 階層を独立したサービスに分割する
- システムを監視し、自動ツールを使用する
大きな進歩を遂げたことをおめでとうございます! 今すぐ自分を叱咤激励してください。素晴らしい!
参考文献
[1] ハイパーテキスト転送プロトコル: https://zh.wikipedia.org/wiki/ハイパーテキスト転送プロトコル
[2] リレーショナル データベース以外にも目を向けるべきでしょうか? :
https://blog.teamtreehouse.com/Should-you-go-beyond-relational-databases
[3] レプリケーション: https://zh.wikipedia.org/wiki/Replication_(コンピューター)
[4] マルチマスターレプリケーション:
https://zh.wikipedia.org/wiki/マルチマスターレプリケーション
[5] MySQL Cluster レプリケーション: マルチマスターおよびリング レプリケーション:
https://dev.mysql.com/doc/refman/5.7/en/mysql-cluster-replication-multi-master.html
[6] キャッシュ戦略と適切な戦略の選択方法:
https://codeahoy.com/2017/08/11/caching-strategies-and-how-to-choose-the-right-one/
[7] R. Nishtala、「Facebook のキャッシュ スケーリング」、ネットワーク システムの設計と実装に関する第 10 回 USENIX シンポジウム (NSDI '13)。
[8] 単一障害点: https://zh.wikipedia.org/wiki/単一障害点
[9] Amazon CloudFront 動的コンテンツ配信:
https://aws.amazon.com/cloudfront/dynamic-content/
[10] クラシック ロード バランサーのスティッキー セッションを構成します。
https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-sticky-sessions.html
[11] マルチリージョン フォールト トレランスのアクティブ-アクティブ (アクティブ-アクティブ):
https://netflixtechblog.com/active-active-for-multi-regional-resiliency-c47719f6685b
[12] Amazon EC2 ハイメモリ インスタンス:
https://aws.amazon.com/ec2/instance-types/high-memory/
[13] スタック オーバーフローを実行するための要件:
http://nickcraver.com/blog/2013/11/22/what-it-takes-to-run-stack-overflow
[14] NoSQL で具体的に何をしているのですか:
http://highscalability.com/blog/2010/12/6/what-the-heck-are-you-actually-using-nosql-for.html
本文翻译自《System Design Interview: An Insider’s Guide》第一章,如有侵权,请联系本人删除
こんにちは、開発7年、外資系5年、インターネット2年のベテランドライバー、しさんです。アーサンやラオメイには勝てますが、PRコメントでダメになったこともあります。長年にわたり、私はパートタイムで働いたり、起業したり、プライベートな仕事を引き継いだり、仕事を混ぜたりしてきました。お金を儲けたし、お金を失った。その過程で、私が最も深く感じたのは、何を学ぶにしても、学び続けなければならないということです。粘り強く続けることができれば、コーナー追い越しを達成するのは簡単です!だから、私が今やっていることをやるには遅すぎるかどうかは聞かないでください。それでも方向性が分からない場合は、私 [パブリック アカウント: More AI (power_ai)] をフォローしてください。そこでは、コーナリングや追い越しのための資本を蓄積するのに役立つ、最先端の情報やプログラミングの知識を頻繁に共有します。