Google Cloud Platform でのスケーラブルで復元力を備えたウェブ アプリケーションの構築

復元力とスケーラビリティを備えたアプリケーションの開発は、アプリケーション アーキテクチャにおいて必要不可欠な要素の 1 つです。うまく設計されたアプリケーションは、需要の増減に合わせてシームレスにスケーリング可能であり、またコンピューティング リソースが失われた場合に対応できる復元力を備えているものです。このドキュメントでは、Google Cloud Platform を使用して、任意のウェブ アプリケーションに広く適用されるパターンとプラクティスを利用し、スケーラビリティと復元力を備えたアプリケーション アーキテクチャを構築する方法について説明します。人気のあるオープンソースのプロジェクト管理ツール Redmine(Ruby on Rails ベース アプリケーション)のサンプル デプロイを介して、このような原則が実世界のシナリオにどのように適用されるのかがわかります。後で(サンプル ソリューションのデプロイで)、アプリケーションを自分でデプロイし、参照するためにすべてのソースをダウンロードできます。

Google Cloud Platform により、スケーラビリティと復元力を備えたウェブ アプリケーションを簡単かつコスト効率よくビルドして実行できます。Google Compute Engine やオートスケーラーなどのサービスを利用することで、需要に応じてアプリケーションのリソースを簡単に調整できます。また、Google Compute Engine の料金設定モデルを使用すれば、秒単位で料金を支払うことになるため、複雑な容量計画や予約計画を立てなくても継続利用割引を利用して最適な料金が自動的に設定されます。

Cloud Platform におけるウェブ ホスティングのオプションの概要については、ウェブサイトの処理をご覧ください。

スケーラビリティと復元力の定義

サンプル アプリケーション アーキテクチャについて説明する前に、用語「スケーラビリティ」と「復元力」を定義します。

スケーラビリティ: 需要を満たすための容量の調整

スケーラビリティの高いウェブ アプリケーションとは、ユーザーが 1 人でも 100 万人でも正常に機能し、適切にトラフィックのピークと低下を自動処理するアプリケーションを指します。スケーラビリティの高いアプリケーションは、必要なときにのみ仮想マシンを追加または削除することで、需要を満たすために必要なリソースのみを消費します。

次の図は、スケーラブルなアプリケーションがどのように需要の増減に対応するのかを示しています。

需要を満たすためにリソースがどのようにスケーリングできるのかを示す図

需要の変化に合わせて容量が動的に調整されている点にご注目ください。設計の弾力性と呼ばれることもあるこの構成は、特定の時点でアプリケーションが必要とするコンピューティング リソースに対してのみ料金を支払うようにするのに役立ちます。

復元力: 予想外の事態に耐える設計

可用性が高い(復元力を備えた)ウェブ アプリケーションとは、システムのコンポーネントの予想どおりまたは予想外の障害が発生しても機能しつづけるアプリケーションです。単一のインスタンスで障害が発生しても、ゾーン全体で問題が発生しても、復元力を備えたアプリケーションはフォールト トレラントのままであり、機能しつづけ、必要に応じて自動的に自己修復します。ステートフルな情報はどのインスタンスにも保存されないため、単一のインスタンスが失われても、さらにはゾーン全体が失われても、アプリケーションのパフォーマンスは影響を受けません。

真に復元力を備えたアプリケーションでは、ソフトウェア開発レベルとアプリケーション アーキテクチャ レベルの両面から計画する必要があります。このドキュメントでは主に、アプリケーション アーキテクチャ レベルに焦点を当てます。

復元力を備えたアプリケーションのアプリケーション アーキテクチャの設計では、通常、以下を行います。

  • ロードバランサでサーバーをモニタリングし、リクエストを最適に処理できるサーバーにトラフィックを分散する
  • 複数のデータセンターでサーバーをホストする
  • 堅牢なストレージ ソリューションを構成する

Google Cloud Platform: 柔軟性と費用対効果が高い

スケーラビリティと復元力をサポートする従来型アーキテクチャでは、多くの場合、リソースに多大な投資が必要になります。オンプレミス ソリューションでは、スケーラビリティは、多くの場合、サーバー容量に過剰に支出してピーク使用量に対応するか、ニーズの平均にのみ合わせて購入し、トラフィックの急増時に不十分なアプリケーションパフォーマンスやユーザー エクスペリエンスのリスクにさらすかを決定することを意味します。復元力では、サーバー容量だけでなく、場所も重要です。暴風雨や地震などの物理的な事象の影響を緩和するために、複数の物理的な場所でサーバーを運用することを検討する必要がありますが、これには多大な費用がかかります。

Google Cloud Platform では、スケーラビリティと復元力をアーキテクチャに追加する柔軟な手段を提供する一連のクラウド サービスという代替手段を提供します。また、Google Cloud Platform は、管理しやすい料金体系を使用して、そうしたサービスを提供します。

Google Cloud Platform を使用した復元力を備えたスケーラブルなアーキテクチャの構築

次の表では、各 Google Cloud Platform サービスが、アプリケーションをスケーラブルで復元力を備えたものにするために必要な主要な要件にどのように対応しているのかを示します。

アーキテクチャ要件 Google Cloud Platform サービス
負荷分散 HTTP 負荷分散
サーバー ホスティング Google Compute Engine リージョンとゾーン
サーバー管理 インスタンス グループ インスタンス グループ マネージャー オートスケーラー
データ ストレージ Cloud SQL Cloud Storage

次の図では、Google Cloud Platform の各コンポーネントがどのように連携してスケーラブルな復元力を備えたウェブ アプリケーションを作成するのかを示します。各コンポーネントが果たす役割の詳細については、後述します。

スケーラブルで復元力を備えたウェブ アプリケーションを示した図

コンポーネントの概要

サンプル アプリケーション アーキテクチャの各コンポーネントは、アプリケーションがスケーラブルで復元力を備えるようにする上で役割を果たします。このセクションでは、各サービスについて簡単に説明します。後述のセクションでは、各サービスの連携について説明します。

HTTP ロードバランサ

HTTP ロードバランサは、顧客がアプリケーションにアクセスするために使用する単一の公開 IP アドレスを公開します。この IP アドレスは、DNS A レコード(例: example.com)または CNAME(例: www.example.com)に関連付けることができます。受信リクエストは、各グループの容量に従って、複数のインスタンス グループに分散されます。ゾーン内では、リクエストは、グループ内の各インスタンスに均等に分散されます。HTTP ロードバランサはトラフィックを複数のリージョンに分散できますが、次のセクションで説明するように、ここでは、複数のゾーンが含まれた単一のリージョンで HTTP ロードバランサを使用しています。

ゾーン

ゾーンとはリージョン内の分離されたロケーションです。ゾーンは、帯域幅が広くレイテンシが低いネットワークで同じリージョンの他のゾーンと接続されています。Google は、1 つのリージョン内の複数のゾーンにアプリケーションをデプロイすることをおすすめします。

インスタンス

インスタンスは、Google のインフラストラクチャでホストされる仮想マシンです。インスタンスは、物理サーバーと同じようにインストールして設定できます。このドキュメントでは、起動スクリプトと Chef を使用して、ウェブ アプリケーション用のアプリケーション サーバーとコードが含まれたインスタンスを設定できます。

インスタンス グループとインスタンス グループ マネージャ

インスタンス グループは、HTTP ロードバランサがターゲットにすることができる一連の同種のインスタンスです。グループのインスタンスは、インスタンス グループ マネージャによって追加、削除されます。実行するゾーンごとにインスタンス グループと対応するマネージャが必要です。

オートスケーラー

Compute Engine Autoscaler は、トラフィック、CPU 使用率、その他のシグナルに応じて、グループのマネージャとのインターフェースとなり、インスタンス グループの Google Compute Engine インスタンスを追加または削除します。サンプル ソリューションでは、オートスケーラーは、HTTP ロードバランサのリクエスト数/秒(RPS)指標に応答します。オートスケーラーは、自動的にスケーリングするようにするインスタンス グループごとに必要です。

Cloud SQL

Google Cloud SQL は、フルマネージドの MySQL データベースです。レプリケーション、暗号化、パッチ、バックアップが Google によって管理されます。Cloud SQL インスタンスは単一のゾーンにデプロイされ、データは他のゾーンに自動的に複製されます。この例で使用している Redmine アプリケーションは、MySQL と互換性があり、Cloud SQL とシームレスに連携します。

Cloud Storage

Cloud Storage により、シンプルでスケーラブルなインターフェースを使用してオブジェクト(通常はファイル)を保存、取得できます。このソリューションでは、Cloud Storage Bucket を使用して、SSL 秘密鍵をスケーラブルな Google Compute Engine インスタンスに配布するとともに、Redmine アプリケーションにアップロードされたすべてのファイルを保存します。したがって、ステートフル情報はどのインスタンスのディスクにも保存されません。

復元力

このサンプル アーキテクチャが復元力を備えるようにするには、障害が発生したインスタンスまたは利用不可になったインスタンスを自動的に置き換えられるようにする必要があります。新しいインスタンスは、オンラインになると、次のようになる必要があります。

  • システムにおける自身の役割を理解する
  • 自動的に自己設定する
  • 依存関係をすべて検出する
  • 自動的にリクエストの処理を開始する

障害が発生したインスタンスを自動的に置き換えるために、以下の複数の Google Compute Engine コンポーネントを組み合わせて使用できます。

起動スクリプトは、インスタンスの起動時または再起動時に実行されます。このスクリプトを使用して、ソフトウェアや更新をインストールして、サービスが仮想マシン内で確実に実行された状態にすることができます。さらには、Chef、Puppet、Ansible、Salt などの設定管理ツールをインストールすることもできます。

このシナリオでは、起動スクリプトを使用して Chef Solo をインストールします。Chef Solo はさらに、アプリケーションと連携するようにインスタンスを設定します。起動スクリプトと Chef Solo を使用してインスタンスを自動的に設定する方法の詳細については、このトピックの末尾にある付録: 新しいインスタンスの追加をご覧ください。

Google Compute Engine インスタンスを起動するには、その前に、起動スクリプトに加え、さらにいくつかの項目を定義する必要があります。たとえば、マシンタイプ、使用するオペレーティング システム イメージ、接続するすべてのディスクを指定する必要があります。このようなオプションは、インスタンス テンプレートを使用して定義します。

インスタンス テンプレートと起動スクリプトを組み合わせて、Google Compute Engine インスタンスを起動する方法と、アプリケーションのアーキテクチャにおける特定の役割を満たすようにそのインスタンス上のソフトウェアを設定する方法を定義します。

起動スクリプト、インスタンス テンプレート、インスタンスがどのように連携するのかを示した図

もちろん、インスタンス テンプレートは単なるテンプレートです。このテンプレートが機能するようにするには、新しい Google Compute Engine インスタンスがオンラインになったときにそのテンプレートをそのインスタンスに適用する方法が必要です。これを実現するには、インスタンス グループ マネージャを使用します。このサービスを使用して、任意の特定の時点に実行するインスタンスの数と、インスタンスに適用するインスタンス テンプレートを決定します。その後、インスタンス グループ マネージャが、必要に応じてインスタンスを起動して設定する処理を担当します。

インスタンス グループ マネージャは、その名前が示すように、インスタンスをインスタンス グループに入れます。インスタンス グループにより、各インスタンスを個別に変更するのではなく、一連のインスタンスを全体として管理できます。

次の図では、以下の各コンポーネントがどのように連携するかを示しています。

  • 起動スクリプト
  • インスタンス テンプレート
  • インスタンス グループ マネージャ
  • インスタンス グループ
起動スクリプト、インスタンス テンプレート、インスタンス グループ マネージャ、インスタンス グループがどのように連携するのかを示した図

インスタンス グループ マネージャとインスタンス グループはゾーン固有のリソースであり、単一のゾーン内に配置されていることに注目してください。複数のゾーンにアプリケーションをデプロイするには、各ゾーンに各リソースを作成する必要があります。一方、インスタンス テンプレートは、任意のゾーン、任意のリージョン内の複数のインスタンス グループ マネージャで再利用できる、プロジェクト レベルのリソースです。

これで、起動スクリプト、インスタンス テンプレート、インスタンス グループ マネージャ、インスタンス グループを使用して、正常でないインスタンスを新しいインスタンスに置き換えることができるシステムが構成されました。次のセクションでは、正常でないインスタンスがどのようなものかを定義し、またそうしたインスタンスを検出する方法を定義できる 1 つの方法を示します。

ヘルスチェック

この時点で、サンプル アプリケーションには、復元力を備えるために必要なほぼすべてのツールが用意されています。ただし、1 つ欠けているものがあります。正常でないインスタンスを特定し、そのインスタンスを置き換える必要があると認識できるようにする方法が必要です。

このアプリケーションは、HTTP ロードバランサを使用して、適切で正常なインスタンスにユーザーを接続するように設計されています。このアーキテクチャにより、リクエストを処理できるインスタンスを特定するために次の 2 つのサービスを使用できます。

  • ヘルスチェック。HTTP ヘルスチェックは、各インスタンスに対してヘルスチェックを実行するためのポートとパスを指定します。ヘルスチェックは、正常なインスタンスから 200 OK レスポンスを予期します。
  • バックエンド サービス。バックエンド サービスは、ロードバランサからトラフィックを受信する必要がある 1 つ以上のインスタンス グループを定義します。バックエンド サービスは、インスタンスによって公開されるポートとプロトコル(たとえば、HTTP ポート 80)に加え、インスタンス グループ内のインスタンスに対して使用する HTTP ヘルスチェックを指定します。

次の図では、アプリケーション アーキテクチャと、どのようにバックエンド サービスと HTTP ヘルスチェックがロードバランサとインスタンス グループに関連するのかを示します。

ヘルスチェックとバックエンド サービスを示した図

Google Cloud SQL を使用したデータの復元力

すべてのアプリケーション アーキテクチャの主要な 3 つの領域は、ネットワーキング、コンピューティング、ストレージです。ここで説明しているアプリケーション アーキテクチャは、ネットワーキング コンポーネントとコンピューティング コンポーネントをカバーしてきましたが、完全なものにするには、ストレージ コンポーネントに対応する必要があります。

このサンプル ソリューションでは、Google Cloud SQL を使用してフルマネージドの MySQL データベースを提供します。Google Cloud SQL を使用して、Google はレプリケーション、暗号化、パッチ管理、バックアップを自動的に管理します。

Google Cloud SQL データベースは、リージョン全体に及びます。つまり、データはリージョン内の各ゾーンに複製されます。これは、データが更新されるたびにバックアップが作成されることと同じことです。1 つのゾーンの完全な障害というめったに起こらない事態が発生した場合でも、データは保持されます。

Cloud SQL では、次の 2 つのレプリケーション タイプから選択できます。

  • 同期レプリケーション。同期レプリケーションでは、更新がクライアントに戻る前に複数のゾーンにコピーされます。これは、重大な問題が起きた場合の信頼性と可用性を高めますが、書き込みは遅くなります。
  • 非同期レプリケーション。非同期レプリケーションでは、書き込みがローカルにキャッシュされた後、かつデータを他の場所にコピーする前に書き込みを確認することで、書き込みのスループットが増大します。非同期レプリケーションでは、レプリケーションが終了するまで待つ必要がないためデータベースへの書き込みが早くなります。ただし、万が一、数秒のデータベースの更新の間にデータセンター システムに障害が起きた場合、最新の更新が失われる可能性があります。

このソリューションで使用されている Redmine アプリケーションでは、ワークロードがあまり書き込みの激しいものではないため、同期レプリケーションを使用しています。ご使用の特定のアプリケーションの特定の書き込みパフォーマンスとデータ耐久性要件に応じて、同期レプリケーションか非同期レプリケーションかを選択する必要があります。

スケーラビリティ

前のセクションでは、サンプル アプリケーションがどのように Google Cloud Platform を使用して復元力を備えたアプリケーションを作成しているのかを示しました。ただし、復元力は十分ではありません。スケーラビリティも重要であるためです。アプリケーションは、ユーザーが 1 人でも 100 万人でも適切に機能する必要があり、またユーザー数に合わせてそのリソースを増減して費用対効果が高くなるようにする必要があります。

アプリケーションのリソースを増減できるという概念には、以下が必要になります。

  • サービスのインスタンスを追加または削除する手段。インスタンスを追加する必要があるタイミングと、インスタンスを削除する必要があるタイミングを決定する手段も必要です。Google Cloud Platform のオートスケーラーを使用すれば、この問題が解決します。
  • ステートフルなデータを保存する手段。インスタンスは稼働したり停止したりするため、ステートフルなデータをインスタンスに保存することはおすすめできません。アプリケーション アーキテクチャで、別個の Cloud SQL インスタンスにリレーショナル データを保存することで、そうしたデータの問題が解決されます。ただし、ユーザーがアップロードしたファイルについて考慮する必要もあります。Google Cloud Storage はこの要件を満たしています。

次の各セクションでは、オートスケーラーを使用して、Redmine アプリケーションを実行しているインフラストラクチャをスケーリングする方法と、アップロードされたファイルに対して Google Cloud Storage を利用する方法について説明します。

オートスケーラーを使用したスケーリング

アプリケーションの使用量は増減するため、必要とされるリソースを動的に調整できる必要があります。Google Compute Engine Autoscaler を使用してこの課題を解決できます。

トラフィックまたは負荷が増加すると、オートスケーラーは追加アクティビティを処理するためにリソースを追加します。一方、トラフィックまたは負荷が低下すると、リソースを削除して、コストを削減できるようにします。オートスケーラーは、定義したスケーリング ルールに基づいて、自動的にこのようなアクションを実行します。その後の人的な介入は不要です。

オートスケーラーの影響には、以下の両面があります。

  1. 需要を満たすために十分なリソースが常に確保されるため、アプリケーション使用の優れたユーザー エクスペリエンスが実現する。
  2. 需要が指定しきい値を下回ったときにオートスケーラーによってインスタンスが削除されるため、コストをより適切に抑制できる。

オートスケーラーは、CPU 使用率、処理容量、または Stackdriver Monitoring 指標に基づいて、仮想マシンの数をスケーリングできます。このソリューションでは、処理容量指標を使用して、インスタンスがロードバランサから受信しているリクエスト数/秒(RPS)に基づいて、Google Compute Engine インスタンスを追加または削除します。オートスケーラーの詳細については、Google Compute Engine Autoscaler を使用したバッチ処理をご覧ください。

リクエスト数/秒(RPS)

前のセクションでは、ロードバランサからトラフィックを受信するためにインスタンス グループを特定する単一のバックエンド サービスについて説明しました。バックエンド サービスに関連付けられたインスタンス グループごとに、このサンプル ソリューションは balancingMode=RATE も設定しています。このプロパティは、maxRatePerInstance プロパティに定義されている RPS(この例では 100 に設定されている)に基づいてバランスを取るようにロードバランサに指示します。この設定は、ロードバランサが各インスタンスを 100 RPS 以下に保つようにすることを意味します。バックエンド サービスの設定プロパティの詳細については、バックエンド サービスのドキュメントをご覧ください。

RPS に基づいてスケーリングするには、自動的にスケーリングする各インスタンス グループに対してオートスケーラーを作成する必要があります。インスタンス グループはゾーンごとのリソースであるため、ゾーンごとにオートスケーラーを作成する必要があることを忘れないでください。

オートスケーラーがアプリケーションのアーキテクチャにどのように収まるのかを示した図

各オートスケーラーには、utilizationTarget プロパティが含まれています。このプロパティは、オートスケーラーが維持する必要がある、ロードバランサの最大処理容量の割合を定義します。この例では、各オートスケーラーの utilizationTarget を、各インスタンスの最大レートである 100 RPS の 80% に設定しています。つまり、RPS がインスタンスごとの最大レートの 80%(80 RPS)を超過すると、オートスケーラーはスケールアップします。RPS がこのしきい値を下回ると、オートスケーラーはスケールダウンします。

インスタンスを追加または削除する必要があるかどうかをオートスケーラーが決定する方法を示したフローチャート

各オートスケーラーでは、オートスケーラーが超過しない最小インスタンス数と最大インスタンス数も定義します。

ファイル アップロードの処理

Redmine アプリケーションの機能の一部として、ログインしているユーザーは、ファイルをアップロード、保存できます。Redmine や他の多くの同様のウェブ アプリケーションのデフォルト動作では、このようなファイルをローカル ディスクに直接保存します。このアプローチは、サーバーが 1 つのみで、適切に定義されたバックアップ メカニズムを備えている場合、問題ありません。しかし、ロードバランサの背後に自動的にスケーリングする複数の Google Compute Engine インスタンスがある場合、これは最適なアプローチではありません。ユーザーがファイルをアップロードした場合、ファイルが保存されたマシンに次のリクエストが届くという保証はありません。また、ファイルが保存されているインスタンスが不要になってオートスケーラーによって終了されないという保証もありません。

優れた解決策となるのが、Google Cloud Storage を使用することです。Google Cloud Storage は、自動的にスケーリングする一連のウェブサーバーから一元的にファイル アップロードを保存したりアクセスしたりするのに最適な場所を提供します。また、Google Cloud Storage は、Amazon S3 クライアントと相互運用可能な API を公開しているため、変更することなく、Redmine S3 プラグインなどの S3 用の既存のアプリケーション プラグインとの互換性を備えています。多くのサードパーティのアプリケーションやオープンソース アプリケーションには、Google Cloud Storage などのオブジェクト ストアをサポートするプラグインが用意されています。独自のアプリケーションを作成する場合、Google Cloud Storage API を直接使用して、ファイルの保存をサポートできます。

Redmine と Google Cloud Storage を使用してファイルをアップロード(青の矢印)、取得(緑の矢印)するフローを以下に示します。

Redmine アプリケーションを介したリクエストのフローを示した図

図で示されているプロセスは、次のとおりです。

  1. ユーザーが、ウェブブラウザからファイルを POST する。
  2. ロードバランサが、リクエストを処理するインスタンスを選択する。
  3. インスタンスが、Google Cloud Storage にファイルを保存する。
  4. インスタンスが、ファイル メタデータ(名前、オーナー、Google Cloud Storage 内の場所など)を Cloud SQL データベースに保存する。
  5. ユーザーがファイルを要求すると、ファイルが Google Cloud Storage からインスタンスにストリーミングされる。
  6. インスタンスが、ロードバランサを介してストリームを送信する。
  7. ファイルがユーザーに送信される。

ストレージ容量

Google Cloud Storage は、Google Compute Engine インスタンスからステートフルなファイルのアップロードを削除して動的にスケーリングできるようにするだけでなく、事実上無限数のファイル アップロード用の冗長な耐久性のあるストレージを提供します。このストレージ ソリューションは、復元力を備えており、スケーラブルで、費用対効果が高いソリューションです。容量計画を気にすることなく、使用したストレージに対してのみ料金を支払うことができ、データは自動的に、複数のゾーンに重複して保存されます。

費用

ここまで、このドキュメントで説明したアプリケーション アーキテクチャでは、Google Cloud Platform を使用して復元力を備えたスケーラブルなアプリケーションを作成する方法を示しています。しかし、アプリの作成には十分ではありません。できる限り費用対効果が高い方法で作成できる必要があります。

このセクションでは、このドキュメントで紹介しているアプリケーション アーキテクチャが復元力を備えていてスケーラブルなだけでなく、費用対効果も高いことを説明します。まず、アプリケーション使用の負荷と頻度について一般的な想定を行い、その想定を基本的な費用の見積もりに変換します。このような想定は単なる想定にすぎないということに留意してください。各数値は必要に応じて自由に調整して、独自のアプリケーションで予想される使用にさらに合うように費用の見積もりを作成してください。

コンピューティング

すべてのアプリケーション アーキテクチャの主要な関心事は、サーバーを稼働しつづけるのにかかる費用です。この費用分析では、次の想定を使用しています。

指標
月あたりの平均ページビュー 20,000,000
月あたりの平均 HTTP リクエスト数 120,000,000
使用ピーク時間(90% 以上) 月曜日から金曜日の午前 7 時から午後 6 時まで
ページビューあたりのデータ転送 100 KB
月あたりのピーク時間 220
ピーク時のリクエスト レート 127 リクエスト/秒(RPS)
オフピーク時のリクエスト レート 6 リクエスト/秒(RPS)

上記の想定に基づいて、毎月の月曜日から金曜日の午前 7 時から午後 6 時までのピーク時にアプリケーションが受け取るページビュー数は、次のように求めることができます。

20,000,000(ビュー/月) x 6(リクエスト/ビュー) x 90%(ピーク時に発生) = 108,000,000

毎月平均して、営業日は 22 日あります。各営業日にピーク時間が 11 時間ある場合、毎月 242 時間のピーク時間を処理するのに十分なコンピューティング リソースを用意する必要があります。

次に、このタイプのトラフィックを処理できる Google Compute Engine インスタンスのタイプを判別する必要があります。このアプリケーション アーキテクチャは、基本的な負荷テストについて gatling.io を使用してテストされ、その結果、タイプが n1-standard-1 の 4 つの Google Compute Engine インスタンスで十分であることがわかりました。

非ピーク時には、このソリューションでは、最小で 2 つの n1-standard-1 インスタンスが実行されます。

インスタンスの実行にかかる費用を知るには、Google Cloud Platform の料金計算ツールで最新の料金の見積もりを確認してください。これを行うと、どちらの場合でも、自動的にインスタンスに継続利用割引が適用されることがわかります。

負荷分散とデータ転送

このアプリケーションは、ユーザーの接続先となる公開 IP アドレスである単一の転送ルールを使用してロードバランサをプロビジョニングしました。この転送ルールは、時間単位で課金されます。

データ転送の見積もりでは、まず、最悪のシナリオを検討します。ロードバランサでは、処理したデータに対して課金されます。つまり、上りと下りの両方のトラフィックが課金されます。120,000,000 HTTP リクエストの 99.5% がユーザーによる Redmine プロジェクト ページの読み込みであると想定します。ページの読み込みは、1 HTTP GET リクエストとしてカウントされ、さらに他のアセット(CSS、イメージ、jQuery)を読み込むために 5 HTTP GET リクエストが発生します。ページ全体を読み込むと、6 HTTP リクエストが発生します。その結果、次のようになります。

  • 月あたり約 20,000,000 回の完全なページ読み込み
  • ページあたり約 450 KB のデータ転送
  • 月あたり合計約 8,955 GB のデータがロードバランサによって処理される

20,000,000 HTTP の残りの 0.5% は、平均サイズ(約 0.5 MB)のファイルをアップロードする HTTP POST リクエストであり、月あたり 500 GB の追加データが処理されます。

この Google Cloud Platform の料金計算ツールの見積もりでは、ロードバランサがこのシナリオで処理する 9,495 GB のデータ転送に対して予想される費用が示されます。

このデータ転送の見積もりは最悪のシナリオです。これは、Google Compute Engine インスタンスからの各リクエストで静的アセットも含めすべてのコンテンツを提供しており、かつキャッシュやコンテンツ配信ネットワーク(CDN)のメリットを享受せずにロードバランサを介しているためです。各ページ読み込みの約 450 KB のペイロードのうち、333 KB は jQuery の読み込みに必要とされていますが、このソリューションが月あたり 2 千万回のページ読み込みに基づいていることを思い出してください。Google がホストしているライブラリから jQuery を読み込むようにアプリケーションの 1 行を更新するだけで、データ転送が 74% 削減されます。

この更新された料金の見積もりでは、Google でホストされているライブラリに切り替えることで実現したデータ転送の削減が示されています。

ストレージ

このソリューションは、Redmine アプリケーションを介してアップロードされたすべてのファイルに対して Google Cloud Storage を使用します。前のセクションで説明したように、その使用の約 0.5% はファイルのアップロードであり、各ファイルの平均サイズは 0.5 MB です。つまり、月あたり 1,000,000 回の新しいファイル アップロードが発生し、結果として月あたり 500 GB の新しいストレージが必要になると見込むことができます。また、このソリューションでは、新しいファイルを保存するために、月あたり 1,000,000 回の HTTP PUT オペレーションを想定していますが、これは、クラス A オペレーションとして課金されます。

Google Cloud Platform の料金計算ツールのこの料金見積もりでは、Google Cloud Storage の使用で予想される費用が示されています。

このアーキテクチャは Cloud SQL を使用して、アプリケーションのすべてのリレーショナル データを保存します。前述のサンプル指標に基づくと、1,024 MB の RAM を使用した D2 データベース タイプで、アプリケーションのワークロードに十分な容量が提供されるはずであり、このデータベースは 1 日 24 時間、週 7 日間稼働することになります。おそらくこのデータベースの使用率は高くなるため、計算ツールの [入出力オペレーション] に対して [多い] オプションを選択します。このサンプル アーキテクチャのテストは、100,000 ドキュメントを挿入することで行われました。その結果、50 GB のディスクで 100,000,000 を超えるドキュメントがサポートされ、上述のレートで使用した場合、このデータベースで 8 年を超える期間においてサポートできることが判明しました。

Google Cloud Platform の料金ツールのこの見積もりでは、アーキテクチャ費用のこの部分に対して予想される費用が示されています。

サンプル ソリューションのデプロイ

このソリューションで説明しているサンプル アプリケーションをデプロイするために、GitHub レポジトリである Google Cloud Platform でのスケーラブルで復元力を備えたウェブ アプリケーションにアクセスします。

付録: 新しいインスタンスの追加

復元力を備えたスケーラブルなアプリケーション アーキテクチャを作成する作業の一環として、新しいインスタンスを追加する方法を決定する必要があります。具体的には、新しいインスタンスがオンラインになったときにそのインスタンスを自動的に設定する方法を決定する必要があります。

このセクションでは、利用可能なオプションのいくつかを見てみましょう。

ソフトウェア インストールのブートストラップ

ユーザーのウェブリクエストを処理するために、各インスタンスでは、データベース接続情報、ファイルの保存先となる Google Cloud Storage バケットの名前などのデータを含む設定データとともに、基本オペレーティング システム上にインストールされた追加ソフトウェアがいくつか必要になります。そのようなコンポーネントをレイヤとして考えると、次のように、各インスタンスで実行されるスタック全体を可視化できます。

ソフトウェアがどのようにインスタンス上にスタックされるのかを示した図

このソリューションでは、インスタンスが起動時に使用する Google Compute Engine イメージを指定するインスタンス テンプレートを使用します。具体的には、このソリューションは、Canonical によって開発されてサポートされている Ubuntu 14.10 イメージを使用します。これは基本オペレーティング システム イメージであるため、アプリケーションによって必要とされる特定のソフトウェアや設定はいずれも含まれていません。

新しいインスタンスが稼働するようになったときにスタックの残りが自動的にインストールされるようにするために、Google Compute Engine 起動スクリプトChef Solo を組み合わせて使用し、起動時にブートストラップできます。起動スクリプトを指定するには、startup-script メタデータ属性項目をインスタンス テンプレートに追加します。起動スクリプトは、インスタンスの起動時に実行されます。

この起動スクリプトは以下を行います。

  1. Chef クライアントをインストールします。
  2. node.json という特殊な Chef ファイルをダウンロードします。このファイルは、このインスタンスで実行する特定の設定を Chef に指示します。
  3. Chef を実行し、詳細な設定を Chef に処理させます。

起動スクリプト全体を以下に示します。

#! /bin/bash

# Install Chef
curl -L https://www.opscode.com/chef/install.sh | bash

# Download node.json (runlist)
curl -L https://github.com/googlecloudplatform/... > /tmp/node.json

# Run Chef
chef-solo -j /tmp/node.json -r https://github.com/googlecloudplatform/...

注: Chef の仕組みの説明は、このソリューションの範囲外です。すべてのレシピとクックブックはオープンソースであり、Google Cloud Platform でのスケーラブルで復元力を備えたウェブ アプリケーションで入手可能です。この例ではこのソリューションの初期リリースに Chef を使用していますが、将来、他の設定プロバイダを追加する予定です。他の実装の pull リクエストがある場合は、このソリューションの GitHub レポジトリの pull リクエストをご利用ください。

アプリケーション設定の提供

新しいインスタンスは、起動して、起動スクリプトと Chef を使用して自己設定した後に、リクエストの処理を開始する前にいくつかの情報を知る必要があります。この例では、各インスタンスは、データベース接続情報(ホスト名、ユーザー名、パスワードなど)、使用する Google Cloud Storage バケットの名前、接続時に使用する認証情報を知る必要があります。

すべての Google Compute Engine インスタンスには、定義可能なメタデータ属性が関連付けられています。前に、特殊な startup-script メタデータ属性について説明しましたが、任意の key=value のペアを追加することもできます。ここでは、インスタンス テンプレート内に属性を指定して、インスタンスがデータベースと Google Cloud Storage バケットに接続する際に必要とする設定データを含めることができます。

GCP Console でインスタンス テンプレートのメタデータがどのように表示されるのかを以下に示します。

インスタンス テンプレートのカスタム メタデータ情報を示している、Google Cloud Platform Console のスクリーンショット

Chef は Ohai というツールを使用して、インスタンスのメタデータからの各設定情報を解析し、テンプレートにデータを入力して、アプリケーションで必要とされる設定ファイルを作成します。適切なメタデータ項目に自動的にアクセスして、データベース接続情報が含まれた database.yaml ファイルを作成するテンプレートを以下に示します。

production:
    adapter: mysql2
    database: <%= node['gce']['instance']['attributes']['dbname'] %>
    host:     <%= node['gce']['instance']['attributes']['dbhost'] %>
    username: <%= node['gce']['instance']['attributes']['dbuser'] %>
    password: <%= node['gce']['instance']['attributes']['dbpassword'] %>
...

また、ローカル メタデータ サービスを使用して、インスタンス内からメタデータ値に手動でアクセスすることもできます。次のように、curl を使用してデータベースのパスワードを取得できます。

curl "http:/metadata.google.internal/computeMetadata/v1/instance/attributes/dbpassword" -H "Metadata-Flavor: Google"

パフォーマンスと依存関係の考慮事項

このソリューションで採用しているブートストラップ アプローチでは、デフォルト オペレーティング システム イメージから開始し、Chef を使用して起動時にすべてのソフトウェアをインストールし、インスタンス メタデータを使用してアプリ設定データを提供しています。

ソフトウェアがどのようにインスタンス上にスタックされるのかを示した図このスタックは、どのように一部のソフトウェアがイメージにバンドルされ、一部のソフトウェアが起動時にインストールされ、一部のソフトウェアが起動後に提供されるのかを示しています。

このアプローチの利点は、システムの設定が Chef のクックブックに指定されていることです。クックブックをバージョン管理、共有、使用することで、Vagrant または Docker を使用してテストのためにローカルに仮想マシンをプロビジョニングしたり、データセンター内または異なるクラウド プロバイダを使用したサーバーを設定したりすることができます。イメージの管理も簡素化します。このサンプル アプリケーションの場合、アプリケーションが使用している 1 つの基本 OS をトラックするだけで済みます。

考慮する必要がある欠点としては、すべてのソフトウェアをインストールするため(場合によっては、コンパイルも必要)、起動時間が長くなる可能性があります。また、この方法に伴う依存関係を考慮することも重要になります。この例では、Chef によって、apt、Rubygems、GitHub から多くのパッケージがインストールされています。新しいインスタンスの起動時に各レポジトリのいずれかが利用不可であった場合、設定が失敗します。

カスタム イメージとブートストラップ

Google Compute Engine では独自のカスタム イメージを作成できるため、ブートストラップのアプローチは、起動時にすべてをインストールするだけではありません。たとえば、以下のことができます。

  1. ベースの Ubuntu 14.10 イメージを起動します。
  2. Redmine アプリを除くすべて(Ruby、nginx など)をインストールします。
  3. 結果からイメージを作成します。
  4. インスタンス テンプレートでそのイメージを使用します。

これで、新しいインスタンスは、起動時に、Redmine をインストールするだけで済みます。起動時間が改善され、外部パッケージ依存関係の数が削減されました。

Redmine を除き、すべてがイメージ上にインストールされたインスタンス スタックを示した図

カスタム イメージ アプローチをさらに進め、すべての依存関係、アプリケーション ソース、設定など、完全にすべてのものをイメージに焼くことができます。これにより、起動時間が最短となり、外部依存関係がゼロになるという利点が得られますが、アプリケーションで何か 1 つでも変更された場合、新しいイメージを作成してインスタンス テンプレートを更新する必要が生じます。

すべてのソフトウェアがイメージにバンドルされているインスタンス スタックを示した図

連続体としてインスタンスをブートストラップするアプローチを検討します。起動時における設定が増加すると、起動時間は長くなりますが、管理するイメージ数は削減されます。カスタム イメージに焼く設定が増加すると、起動時間は短縮し、依存関係が削減されますが、管理するイメージ数が増加する可能性があります。ほとんどのお客様にとって、適切なアプローチは、双方の間のどこかにある妥協点です。お客様、そしてご使用のアプリケーションにとって妥当なアプローチを選択してください。

ソフトウェアがインスタンス上にインストールされる一連の方法を示した図範囲は、すべてが起動後にインストールされるようにする方法から、すべてがイメージにバンドルされるようにする方法までです。
このページは役立ちましたか?評価をお願いいたします。

フィードバックを送信...