クラウド用のアプリケーションを設計する

非常に高度なクラウド・アプリケーションを実現するための、設計に関する基本的な考慮事項

デプロイ、保守、スケーリングが容易なクラウド対応のアプリケーションを設計する方法を学びましょう。この記事では、読み取り専用のファイルシステムの設計から、イベント・ソーシングのようなアーキテクチャー・パターンの設計に至るまで、クラウド・ベースのコンピューティング・プラットフォーム上でアプリケーションを容易に実行できるようにする方法を説明します。

Peter Bell, CEO, SystemsForge

Peter BellPeter Bell はクラウド・デプロイメントや、アジャイル・アーキテクチャー、NoSQL、ドメイン特化言語と要件、見積もりなどに関し、世界中で講演を行い、幅広い著作活動を行っています。彼はさまざまなチームに対し、要件収集や、見積もり、プロジェクト管理プロセスのみならず、エンジニアリング・プラクティスや使用するツールについても改善することによって、適切なソフトウェアを短時間に開発できるように支援を行っています。彼はイギリス、ケンブリッジの Code Generation カンファレンスのプログラム委員であり、また SPLASH の Domain Specific Modeling ワークショップに参加しています。



2011年 7月 08日

クラウド・コンピューティングは、アーキテクトが設計に使用する手段の中でも重要なものの 1 つです。クラウド・コンピューティングを利用すれば、サーバーの構成を気にせずにプロジェクトのプロトタイピングをすることや新しいプロジェクトを立ち上げることができます。また、サーバー管理に伴うコストやリスクを削減することもできます。さらに、必要に応じていつでも追加のインスタンスを起動することができるため、スケーリングを容易に行うことができます。

よく使われる頭文字語

  • SSL: Secure Sockets Layer
  • TPS: Testing Procedure Specification
  • UUID: Unique User ID

その一方で、クラウド用のアプリケーションを開発するにあたっては、考慮する必要があるアーキテクチャー上の問題点がいくつもあります。この記事では、クラウド・ベースのアプリケーションを初めて設計する際に考慮が必要となる事項のいくつかに焦点を当てて説明します。

クラウド・コンピューティングの利点

クラウド用のアプリケーションを設計する際の推奨事項を説明する前に、クラウド・ベースのアーキテクチャーによってもたらされる利点について、少し復習しておきましょう。

  • 製品化に要する時間: 新しいアプリケーションの開発に取り組む場合、インフラストラクチャーのプロビジョニングに時間をかける代わりに、機能の開発に集中することができます。また、サーバーの購入や、セットアップ、構成にかかる時間も不要となります。経験を積むと、午前中に概念実証のコーディングを行い、同じ日の午後にはそのコードをクラウド・サーバー上で実行することもできます。
  • スケーリング: アプリケーションの負荷がどの程度になるかわからないことは珍しくありません。そのため、現実にはありえないような負荷を想定して過剰にプロビジョニングしてしまうことと、プロビジョニングが不十分でパフォーマンスの問題が生じてしまい、追加のハードウェアを購入し、構成してデプロイしなければならない状況との間にある、わずかな適正プロビジョニングの範囲を探さなければなりません。クラウド・ベースのインフラストラクチャーを利用すると、最初は最小限の数のインスタンスを起動し、負荷が増加した場合にはインスタンスの数を自動的に増やしてスケール・アウトすることができます。
  • 柔軟性: クラウド・ベースのインフラストラクチャーでは自動的にスケーリングが行われるため、サーバー・インスタンスの数を動的に変更することができます。そのため、ピーク負荷 (1 日のうちの特定の時間帯、特別なイベントを起動する場合、広告を実行する場合、など) と平均的な負荷との間に大きな差がある場合にも、ピーク負荷に備えて常時十分なインスタンスをプロビジョニングしておくために費用を支払う必要はありません。
  • 単純さ: スケーラブルなアプリケーションを社内で設計、構築、デプロイするためには、複雑な作業を多数こなす必要があります。具体的には、ロード・バランサーを検討、選択、構成したり、ハードウェア障害の際に IP アドレスの再構成を行うソリューションを作成したり、メッセージング・ベースのスケーラブルな E メール・サービスを設計したり、重要データのためのバックアップ機能および障害回復機能の実装方法を検討したりする必要があります。ほとんどのクラウド・プロバイダーは、こうした問題に対して実績のあるソリューションを用意しており、ユーザーはそれらのソリューションを利用することができます。
  • テストの容易さ: クラウド・ベースのインフラストラクチャーを使用する場合、機能テスト用または負荷テスト用に、追加のインスタンスを容易に起動することができます。そのため、テストを実行するために常時使用可能な高価なハードウェアを維持する必要はありません。
  • 初期コスト: クラウド・コンピューティングには先行投資の必要がないため、新しいプロジェクトの製品化コストを削減することができます。またホスティング・コストが問題になってくるのは、アプリケーションがよく利用されるようになってからの話であるため、嬉しい問題となります。
  • 障害回復: アプリケーションをクラウド用に設計、開発する必要があるということは、大抵の場合、重要データのバックアップや、ハードウェア障害およびネットワーク障害からの自動回復が非常に容易になるということです。

クラウド用にアプリケーションを設計する

小規模なアプリケーションであってもクラウドを使用する意味は十分にあるため、クラウド・ベースのアプリケーションは、多くのアーキテクトにとって規模に合わせて効率的な設計を行う第一歩となります。アプリケーションをスケール・アウトする際には考慮すべき事項がいくつもありますが、それらの事項は単体サーバーのパフォーマンスを最大化することに慣れたアーキテクトにとっては直感的なものではないかもしれません。

スケール・アップとスケール・アウト

開発したアプリケーションの利用者が増えてくると、そうした経験が初めての場合、通常はまずアプリケーションのスケール・アップを行います。RAM を追加し、プロセッサーの速度を上げ、高速のハードディスクにアップグレードし、処理時間のかかるクエリーや共通する計算のためにキャッシュを実装します。これらはどれも妥当な手法ですが、そのアプリケーションをあるレベル以上にスケーリングする必要がある場合には、単なるスケール・アップではなく、複数サーバーにわたるスケール・アウトが行われるように設計する必要があります。スケール・アウトを行うためには、アプリケーションのアーキテクチャーの大幅な変更が必要になることも珍しくありません。クラウド・アプリケーションが持つ特有の性質を考えると、クラウド・アプリケーションの設計では初めからスケール・アウトを考慮しておく必要があります。

また、クラウド用のアプリケーションを設計する場合、細かなパフォーマンスの最適化に時間をかけないようにすることが重要です。複雑なキャッシュやパフォーマンスの微調整に長い時間を費やすよりも、単純な設計を維持し、アプリケーションを確実にスケール・アウトできるようにした方がはるかに得策です。一般に、開発者にかかるコストよりもサーバーのコストの方がはるかに安価であるため、細かなパフォーマンスの最適化を行っても、開発者がそれに費やした時間とアプリケーションの保守性が低下することに見合った価値を得られないケースがほとんどです。

スケール・アウトを行う際の重要な考慮事項

アプリケーションをスケール・アウトする必要がある場合には、以下の 5 点を十分考慮して設計を行う必要があります。

  • 可変状態を最小限にする
  • NoSQL データ・ストアを検討する
  • 非同期サービスを作成する
  • デプロイメントを自動化する
  • 障害に備えた設計をする

可変状態を最小限にする

クラウド内で水平スケーラビリティーを高める上でおそらく最も重要なことは、可変状態を最小限にすることです。その理由は、関数型プログラミング言語が非常に一般的になりつつあり、イベント・ソーシング (詳細については「参考文献」のリンクを参照) のようなパターンが適用されることが非常に多くなっているからです。可変状態が共有されると (つまり変数がアプリケーション全体にわたって共有され、時間と共に変更される可能性がある場合には)、スケーラビリティーの面で大きな問題を引き起こします。複数のサーバーやプロセスが同じ変数を同時に更新しようとするため、デッドロックやタイムアウト、トランザクションの失敗などが発生することにつながります。あるアプリケーションにおいて、可変状態を最小限にする、または削除する必要がある場所としては、Web サーバー上、アプリケーション内、そして (場合によっては) データベース内が挙げられます。

不変のファイルシステム

クラウド・アプリケーションでは、いかなるインスタンスであっても、障害が発生しないという保証はありません。Web サーバー・インスタンスが 3 つあり、そのすべてがリクエストを処理している場合、どのインスタンスにも、突然障害が発生する可能性があります。それを考慮し、サーバー・インスタンスの障害時に失われても構わない情報のみをローカル・ファイルシステムに保存する必要があります。

ユーザーが (プロファイルの画像であれ TPS レポートであれ) ファイルをアップロードする場合には、ユーザーがアクセスする Web サーバー上のハードディスクにアップロードするだけでなく、冗長なリモート・ファイルシステムにも確実にアップロードする必要があります。サーバー・インスタンスの障害時であっても必ずアクセスする必要がある情報をログに記録する必要がある場合には、任意の Web サーバーのローカル・ハードディスクに情報を永続化するのではなく、Cassandra のような NoSQL ストアに保存するようにします。

不変のアプリケーション

共有された可変状態は、特にオブジェクト指向プログラミングでは役に立ちます。しかし、クラウド・ベースのアプリケーションをスケーリングする際には、可変状態を最小限にとどめ、可変状態が何を意味しているかを注意深く考えることが重要です。

Eric Evans 氏は、彼の著書『Domain Driven Design』の中で、可変状態を最小限にとどめるための優れたコード・レベルのパターンをいくつか紹介しています。その一例は、(可変の) エンティティーを可能な限り最小限にとどめ、アプリケーションの状態として (不変の) 値オブジェクトを可能な限り使用する、といったものです。このパターンに従うと、可変エンティティーとして表されるユーザーに対し、不変の値オブジェクトを使ってユーザーの住所を表現すれば、そのユーザーが引っ越した場合でも、そのユーザー用に指定された住所を変更するだけで済みます。一般に、可変状態を使用するよりも値オブジェクトおよび不変の値を使用するようにします。これは、クラウド・ベースのアプリケーションの多くの部分によって定期的に更新が必要となる可能性のある状態の場合、特に言えることです。

また、キャッシング戦略についても注意深く検討する必要があります。1 つのインスタンスに固有の情報であれば、ローカル・キャッシュで構いません。そのインスタンスが動作を停止した場合でも、ローカル・キャッシュはいつでも再作成できるからです。しかし、別の Web サーバーにアクセスしているユーザーにとって必要となる可能性のある情報の場合には、その情報を共有の永続ストアから毎回取得するか、あるいは複数の Web サーバー・インスタンス全体にわたってキャッシュを更新する分散キャッシュを使用する必要があります。

不変のデータ・ストア

不変のデータ・ストアというのは、最初は矛盾した表現のように聞こえるかもしれませんが、イベント・ソーシングの要素を取り込んだ手法を用いてクラウド・ベースのアプリケーションのデータベース設計を行うと、実際にメリットがある場合があります。アプリケーションをスケーリングしようとする際に発生する一般的な問題としては、データベースへの書き込みの競合が挙げられます。例えば、ある発注書に 1 ヶ所変更を加えると、何百件もの発注品目や、複数のベンダー向けの関連する発注書に影響がでる可能性があるとします。その場合、当然のことですが、一連の変更の一部のみが実施された無効な状態にデータベースが決して陥らないようにするため、そうした変更はすべてトランザクションの中にラップされなければなりません。しかし、関連する発注に影響を及ぼすような変更が含まれるトランザクションを、ますます多くのユーザーが実行するようになるにつれ、オプティミスティック・ロックの競合が原因で、すべてのトランザクションがすぐに失敗するようになってしまいます。

この問題に対処する 1 つの方法は、データベースの可変状態を最小限にすることです。ユーザーは、苗字や、名前、その他のプロフィールのフィールドに対して可変の値を持つ代わりに、一意の識別子 (例えば、ID、E メール・アドレス、UUID など) を持ち、それ以外の状態は持たない 1 件のレコードをデータベースに持つようにします。そして ProfileUpdateEvent のための別のテーブルを用意し、変更があるたびに必ず、不変イベントをそのイベントが発生したタイム・スタンプと共にそのテーブルに保存するようにします。つまりユーザーが住所 (home city) を変更すると、home_city フィールドの新しい値と変更が行われた日付と時刻が保存され、ProfileUpdateEvent が発生します。ユーザーの住所 (home city) を取得するためには、単純に ProfileUpdateEvent をすべて検索し、home_city フィールドの変更が行われたタイム・スタンプのうち、最も新しいものを見つけます。このプロセスによって、システムでは書き込みの競合が起こらなくなり、読み取り時、あるいは自動化されたスケジュールで発生するいかなる競合も解決されるため、アプリケーションの書き込みのスケーラビリティーが大幅に高くなります。

もちろん、読み取りパフォーマンスの問題もあります。単に 1 つのエンティティーの状態を取得するだけのために、多くのイベントに対して処理を実行しなければならないとしたら、それは非効率であり、読み取りのスケーラビリティーが問題となるアプリケーションの場合はなおのことです。しかし、この問題は容易に解決することができます。ユーザー・テーブルに追加のフィールドを再作成し、これらのフィールドをユーザーの状態に対する唯一の信頼できる参照にするのではなく、ある時点のユーザーの状態の単なるキャッシュにするのです。そして、ビジネス・ルールに応じて、ユーザー・テーブルの中にある状態のキャッシュを ProfileUpdateEvent 発生時に更新するスクリプトを作成することで、そのビジネス・ルールに基づく書き込みの競合を解決できるようになります。このように、クラウド・ベースのアプリケーションをスケーリングする上で、書き込みの競合が実際に障害になりそうな場合には、イベント・ソーシングを検討する価値があります。


NoSQL データ・ストアを検討する

データベースにおける書き込みの競合を管理するもう 1 つの方法は、アプリケーション・データの一部またはすべてに対して NoSQL データ・ストアを使用する可能性を検討してみることです。例えば Cassandra は、膨大な量のデータを格納する場合に、複数ノードにわたってリニアな書き込みスケーラビリティーを実現できるように特別に設計されています。CouchDB は、複数ノードにわたってマスターから別のマスターへと同期できる優れた機能を持っています。また MongoDB には「カウンター」フィールドという概念があり、このフィールドを更新する場合には非同期更新を実行しさえすれば、その後の処理はすべて MongoDB が行ってくれます。そのため、投稿の閲覧数を定期的に更新するだけであれば、書き込みの競合を気にする必要がなくなります。

多くの NoSQL ストアには MapReduce 機能も用意されており、定義済みのクエリーを効率的に利用することができます。大規模なデータ・セットに対して定義済みのクエリーを実行している場合には、NoSQL ストアは、扱うデータ量の増大に伴ってスケーリングされるソリューションを提供することができます。


非同期サービスを作成する

もう 1 つの重要な設計手法は、非同期サービスを別個に作成することによってメインのアプリケーション・サーバーの負荷を減らす方法です。同期的な E メールの送信やレポートの実行が完了するのを待っている間、スレッドをブロックしてサイト訪問者に応答を待たせなければならないわけではありません。こうした種類のタスクは別個のサービスに分割し、それらのサービスをクラウド内の別々のサーバーで実行した方がはるかに適切です。そうすることで、それらのタスクをメインのアプリケーションとは独立した形でスケーリングすることができます。タスクの終了を待っている間 Web サーバーのスレッドをブロックする必要はなく、ユーザーは「プロセスは進行中です。プロセス終了時には通知されます」という応答を得るために、プロセスが終了するのを待つ必要はありません。

通常、非同期サービスに接続する場合には、ある程度送達が保証されたトランスポート・メカニズム (メッセージ・キューなど) を使用します。また、プロセス間通信ではなくネットワークを利用することも重要です。一般に、これらのサービスは別々のサーバーで実行しますが、そのような選択をした場合には、確実にこれらのサービスを別々のサーバーで実行できなければなりません。また、別の設計手法を用いることもできます。例えば、別個の非同期サービスを実行するさまざまなサービスと、メインのアプリケーションとの間で情報を共有するために書き込む対象として、データベースを扱う方法などです。


デプロイメントを自動化する

最後に、クラウドのデプロイメント・プロセスを自動化することが重要です。さまざまなロール (Web サーバーや、E メール・サーバー、データベース・サーバーなど) のベースとなるマシン・イメージが必要であり、また Chef や Puppet などのツールを使用してインスタンスを自動構成する必要があります。コードを自動的にデプロイするために、何らかのビルド・システムも使用する必要があるでしょう。

クラウド・ベースのアプリケーションの監視も重要な考慮事項です。インスタンスに障害が発生したことやインスタンスの負荷が重くなったことが検出できるように監視をセットアップすることで、アプリケーションのパフォーマンスに応じて、自動的にインスタンスを追加で起動したり、あるいはインスタンスを減らしたりすることができるようになります。

データ・センターに障害が発生した場合に対応するために、スクリプトによって IP アドレスの再マッピングが自動的に行われるようにする必要があります。また、クラウド・プロバイダーがどのように SSL 接続をサポートしているかを調べ、さまざまなインスタンスへの SSL 接続を行ってください。通常、適切なプラクティスとしては、プロトコルで提供されるトランスポートのセキュリティーが絶対に必要なページにのみ SSL を使用するようにします。というのも、SSL リクエストにはオーバーヘッドが伴うため、SSL の使用によってビジネスの価値が高まる場合にのみ、セキュリティーのためのコストを払うようにする必要があるからです。

デプロイメントの自動化、および活発化している DevOps の動向について詳しく学ぶには、「参考文献」に挙げた Jez Humble 氏と David Farley 氏の共著による継続的デリバリーについての優れた本を読んでください。


障害に備えた設計をする

クラウド・ベースのアプリケーションでは、障害の発生を考慮して設計することが特に重要です。例えば、単一障害点を調べ、その単一障害点に障害が発生した場合に何をすべきかを検討するなど、最悪のシナリオについて十分考えを巡らす必要があります。

ただし、どの程度のレベルの障害ならば許容できるかを決めることも、同じくらい重要です。データ・センターに障害が発生した場合、別のデータベースを「マスター」に格上げするまでの数分間はサーバーへのアクセスが読み取りアクセスしかできなくても許されるかもしれません。サーバーに障害が発生した場合、ユーザーが再度ログインする必要があったり、そのユーザー・プリファレンスや買い物かごの中身が失われたりしても許されるかもしれません。耐障害性のために必要となるエンジニアリング・コストと、その耐障害性によってもたらされるビジネスの価値とを比較し、ビジネスにとってそれほど重要ではない情報には、冗長性を持たせるための過剰な投資をしないことが重要です。


まとめ

クラウド・ベースのアプリケーションには、多くの利点があります。製品化に要する時間が短縮されたり、スケーリングが容易に行えたりすることに加え、初期コストが低く、適切に設計されたクラウド・ベースのソリューションは、概して非常に優れた障害回復機能を提供します。ただし、クラウド・ベースのデプロイメントを活用するためには、クラウドに合った方法で設計する必要があります。つまり、一般的にはローカル・ファイルシステムは読み取り専用とし、重要なデータはすべてデータベースまたは共有の永続ファイルシステムに格納するようにします。また、アプリケーションのスケーラビリティーを向上させるために、アプリケーションの可変状態を最小限にとどめ、NoSQL データ・ストアを使うことを検討してください。重い処理は非同期サービスに分割し、その非同期サービスを別々のサーバーに移せないかどうかを調べます。最後に、デプロイメント・プロセスを自動化し、また障害発生時にクラウド・ベースのアプリケーションのパフォーマンス特性が許容レベルとなるように、障害を考慮してアプリケーションを設計します。

参考文献

学ぶために

製品や技術を入手するために

  • IBM SmartCloud Enterprise で利用可能な製品イメージを調べてみてください。
  • 自動化されたオープンソースのシステム統合フレームワークである Chef について調べ、Chef をダウンロードしてください。
  • クラウド・ベースの大規模なアプリケーションの構築に Puppet を活用することができます。

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Cloud computing
ArticleID=696823
ArticleTitle=クラウド用のアプリケーションを設計する
publish-date=07082011