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

復元力とスケーラビリティを備えたアプリケーションの開発は、アプリケーション アーキテクチャにおいて必要不可欠な要素の 1 つです。適切に設計されたアプリケーションであれば、需要の増減に合わせてシームレスにスケーリング可能であり、またコンピューティング リソースが失われた場合に対応できる復元力を備えています。

このドキュメントは、Compute Engine に精通したシステム運用の専門家を対象としています。このドキュメントでは Google Cloud Platform で、任意のウェブ アプリケーションに広く適用されるパターンとプラクティスを利用して、スケーラビリティと復元力を備えたアプリケーション アーキテクチャを構築する方法について説明します。人気のあるオープンソースのプロジェクト管理ツール Redmine(Ruby on Rails ベースのアプリケーション)をデプロイする例を通して、このような原則が現実のシナリオにどのように適用されるのかを示します。後で(サンプル ソリューションのデプロイのセクションで)、アプリケーションを自分でデプロイして、参照用のソースをすべてダウンロードできます。

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

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

始める前に

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

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

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

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

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

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

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

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

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

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

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

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

Google Cloud Platform: 柔軟性とコスト効率に優れたプラットフォーム

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

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

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

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

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

次の図に、これらの GCP コンポーネントが連携して、スケーラビリティと復元力を備えたウェブ アプリケーションを構築する仕組みを示します。各コンポーネントが果たす役割については、次のセクションで詳しく説明します。

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

コンポーネントの概要

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

HTTP ロードバランサ

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

ゾーン

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

インスタンス

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

インスタンス テンプレート

インスタンス テンプレートは、マシンタイプ、イメージ、ゾーン、ラベル、その他のインスタンス プロパティを定義します。インスタンス テンプレートを使用して、マネージド インスタンス グループを作成できます。

マネージド インスタンス グループ

マネージド インスタンス グループとは、インスタンス テンプレートに基づく同種のインスタンスからなるグループのことです。HTTP ロードバランサは、マネージド インスタンス グループをターゲットに、そのグループに含まれるインスタンス全体で処理を分散できます。マネージド インスタンス グループには対応するインスタンス グループ マネージャ リソースがあり、このマネージャによってグループのインスタンスが追加、削除されます。

オートスケーラー

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

Cloud SQL

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

Cloud Storage

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

復元力

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

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

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

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

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

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

インスタンス テンプレートと起動スクリプトの組み合わせにより、Compute Engine インスタンスを起動する方法と、アプリケーション アーキテクチャでの特定の役割を満たすようにそのインスタンスでソフトウェアを構成する方法が定義されます。

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

もちろん、インスタンス テンプレートは単なるテンプレートです。このテンプレートを機能させるには、新しい Compute Engine インスタンスがオンラインになった時点で、そのインスタンスにテンプレートを適用する手段が必要になります。その手段として作成するのが、マネージド インスタンス グループです。任意の時点で実行するインスタンスの数、そしてそれらのインスタンスに適用するインスタンス テンプレートを決定します。インスタンス グループ マネージャは、必要に応じてそれらのインスタンスを起動し、構成します。

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

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

マネージド インスタンス グループと、それに対応するインスタンス グループ マネージャは、ゾーン固有のリソースにすることも、リージョン リソースにすることもできます。インスタンス テンプレートはプロジェクト レベルのリソースであるため、任意のゾーンの任意のリージョン内にある複数のマネージド インスタンス グループで再利用できます。ただし、インスタンス テンプレートで一部のゾーンリソースを指定した場合、そのテンプレートを使用できるのは、それらのリソースがあるゾーンに限定されます。

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

ヘルスチェック

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

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

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

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

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

Cloud SQL でのデータの復元力

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

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

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

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

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

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

スケーラビリティ

前のセクションで、サンプル アプリケーションで GCP を使用して、復元力を備えたアプリケーションを作成する方法を説明しました。ただし、復元力だけでは不十分で、スケーラビリティも重要です。アプリケーションは、ユーザーが 1 人でも 100 万人でも適切に機能する必要があり、ユーザー数に合わせてそのリソースを増減してコスト効率を高めなければなりません。

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

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

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

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

アプリケーションの使用量は増減するため、必要とされるリソースを動的に調整できなければなりません。この課題を解決するために使用できるのが、Compute Engine オートスケーラーです。

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

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

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

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

リクエスト数/秒(RPS)

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

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

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

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

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

各オートスケーラーでは、オートスケーラーが維持すべき最小インスタンス数と最大インスタンス数も定義します。

自動スケーリング機能は、マネージド インスタンス グループでのみ使用できます。詳しくは、インスタンス グループインスタンスのグループの自動スケーリングをご覧ください。

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

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

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

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

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

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

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

ストレージ容量

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

料金

ここまで、このドキュメントで説明しているアプリケーション アーキテクチャで、GCP を使用して、復元力とスケーラビリティを備えたアプリケーションを構築する方法を示しました。ただし、可能な限りコスト効率の高いアプリケーションを構築するためには、それだけでは足りません。

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

コンピューティング

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

指標
月あたりの平均ページビュー 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 時間のピーク時間を処理するのに十分なコンピューティング リソースを用意する必要があります。

次に、このようなタイプのトラフィックを処理できる Compute Engine インスタンスのタイプを明らかにする必要があります。このアプリケーション アーキテクチャは、基本的な負荷テストについて gatling.io を使用してテストされ、その結果、タイプが n1-standard-1 の 4 つの 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 回の完全なページ読み込み
  • ページあたり約 10 KB の上りデータ処理および約 450 KB のデータ転送
  • ロードバランサにより月あたり合計約 214 GB のデータが処理され、9,091 GB の下りトラフィックが発生

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

Google Cloud Platform の料金計算ツールによるこの見積もりから、このシナリオでロードバランサが処理する 714 GB のデータ転送と 9,091 GB の下りトラフィックに対する料金がわかります。

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

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

ストレージ

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

Google Cloud Platform の料金計算ツールによるこの料金見積もりから、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 でのスケーラブルで復元力を備えたウェブ アプリケーションにアクセスします。

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

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

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

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

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

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

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

新しいインスタンスが稼働するようになったときにスタックの残りが自動的にインストールされるようにするために、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 を使用して自己構成した後に、リクエストの処理を開始する前にいくつかの情報を把握する必要があります。この例で、各インスタンスが把握しなければならない情報は、データベース接続情報(ホスト名、ユーザー名、パスワードなど)、使用する Cloud Storage バケットの名前、そして接続に使用する認証情報です。

すべての Compute Engine インスタンスには、メタデータ属性が関連付けられています。これらの属性は、ユーザーが定義できます。前に、特殊な startup-script メタデータ属性について説明しましたが、任意の Key-Value のペアを追加することもできます。ここでは、インスタンス テンプレート内で属性を指定して、それらの属性に、インスタンスがデータベースと 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 から多くのパッケージがインストールされています。新しいインスタンスの起動時に各リポジトリのいずれかが利用不可であった場合、構成が失敗します。

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

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

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

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

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

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

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

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

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

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