Furyu

[フリュー公式] Tech Blog

フリュー株式会社の技術ブログです

2011年08月9日

Amazon Web Services 1ヶ月導入記 part 2 アーキテクチャ設計編

みなさん、こんにちは!フリューでモバイルサイト開発を行っている鷲見といいます。

現在、あるソーシャルプラットフォーム上のアプリケーションを構築するプロジェクトでの、クラウド環境の導入の進行状況をそのまま記事にしています。

前回まででAmazon Web Servicesを利用することを決定し、データベースにはSimpleDBを利用するところまで決定しました。

クラウド1ヶ月導入記 part 1 比較編
クラウド1ヶ月導入記 part 2 見積編
Amazon Web Services 1ヶ月導入記 part 1 データベース編

今回のテーマはアーキテクチャ設計です。

AWSを利用したアプリケーションの全体的なアーキテクチャを検討していきたいと思います。

今回構築するシステムに求められる要件とアーキテクチャ設計手法について、比較検討しながら最終的な構成を決定していきます。


アーキテクチャ設計手法

AWSを用いたアーキテクチャ設計手法についてはAmazon Web Servicesの日本法人、Amazon Data Services Japanのエバンジェリスト・玉川憲さんらがWebで行われたセミナーの資料があるので、私が紹介するまでもなく、そちらを参考にするのがよいでしょう。

このWebセミナーを実は社内でヘッドフォンしてノートPCを凝視しながら受講していました。周りの視線が痛かったというのは多分気のせいです。

さて上記Webセミナーを受講して、私が特に印象に残ったのは以下の2点です。

トレードオフ

よくよく考えれば当たり前のことなのですが、クラウドで環境構築をしたからといって止まらないシステムになるわけではありません。

残念ながらAWSを含むクラウドは銀の弾丸ではありません。

とうぜんながらクラウドでも耐障害性の強い環境を構築するのにはお金がかかります。そのあたりの要件とお金のすり合わせの重要性というところはクラウドでも変わらないという点を再認識できたという点で印象に残りました。

故障のための設計

全てが故障する前提で設計する。

なんかとても深い言葉です。

いままでの耐故障性をあげるために故障を起きないようにしていたのに、故障はするから故障に備えて設計するようにというのはとても印象的でした。

AWSでのアーキテクチャ設計はなんといってもここに尽きるんじゃないだろうかと思います。

このケースでのアーキテクチャ設計のポイントはおそらく2種類あって

  • 故障が発生した場合でも縮退運転できるようにする
    • 単一障害点(SPOF)を作らない
    • 複数AZへのEC2インスタンスの配備
    • 各コンポーネントを疎結合にしておく(サーバ台数が減っても動くように)
  • 故障が発生するような高負荷状態が発生した場合、負荷を分散できるようにする
    • 高負荷状態のモニタリング
    • オートスケール
    • 各コンポーネントを疎結合にしておく(サーバ台数が増えても動くように)

という対応がとれるのだと思います。

どちらのアプローチをとるのであっても、各コンポーネントを疎結合にしておき、コンポーネントを構成する要素が減っても、増えても稼働することというのは、耐障害性の高いアプリケーションを構築すうる上で重要なところだと思います。


要件

今回のアプリケーションの要件としては、ソーシャルアプリケーションなので、サービスのダウンタイムが売上減に直結するので、出来る限りサービスを落としたくありません。

要件としては

  • SPOFは作らない
  • Web/APサーバはスケールアウトし負荷分散できること
  • Web/APサーバは全Web/APサーバがダウンしない限りサービスを提供し続けられること

などが挙げられます。


最終構成

上記の要件と設計手法を考慮した結果、以下のようにアーキテクチャ設計を行いました。

  • 日本国内向けのサービスのため、Regionは東京リージョンとする。
  • Web/APサーバは単一でも複数でも稼動可能な構成とし、サーバ数の増加で負荷分散できるようにする。
  • AvailabilityZone(AZ)全体の障害に備えて、複数のAZにEC2のインスタンスを配置する。
  • 複数AZでのロードバランシングを行うため、Amazon ELBを利用してロードバランシングする。
  • 障害に備えEBSのスナップショットをS3に保存する。
  • DNSにはオートスケールを行うAmazon Route53を利用する。
  • データを自動的に複数AZにコピーし、負荷分散・スケーリングも自動で行うSimpleDBを利用する。

この設計結果の構成を図にするとこのようになります。



※この図はCacooを使って作成しています。


まとめ

この記事では、

  • AWSを用いたアーキテクチャ設計手法の紹介
  • 実際のアーキテクチャ設計

を行いました。

大事な点は『全てが故障する前提で設計する。』ということです。

アーキテクチャ設計も完了したので、次回はAmazon SimpleDBの詳細について紹介していきたいとおもいます。


2011年08月2日

Play frameworkでWebSocketを使う

こんにちは。フリュー モバイル事業部の九岡です。 今回はPlay frameworkのWebSocketサポートをご紹介します。

WebSocket

WebSocketとは、WebブラウザとWebサーバ間でリアルタイムに双方向通信を行うための通信方法です。

ブラウザ-サーバ間のリアルタイムな双方向通信は、これまでもFlashやAppletでソケット通信を使えばできましたが、

  • JavaScriptから直接アクセスできない
  • Webの範囲外であるが故にWebフレームワークが対応しておらず、サーバ側の実装も面倒くさい

という難点がありました。

そこでWebSocketです。
双方向通信の仕様がWebSocketとしてブラウザに取り込まれる事で、実装の敷居が下がりました。

  • 最近流行のHTML5+JavaScriptのクライアントアプリにちょっと手を入れるだけで双方向通信に対応できる
  • 巷のWebフレームワーク等のサポートが始まり、サーバ側の実装コストも低い

Play framework meets WebSocket

さて、本題のPlay frameworkですが、バージョン1.2からWebSocketをサポートしています。
Play frameworkはMVCアーキテクチャに基づいたWebフレームワークですが、
C層にWebSocketControllerというものが追加されました。
これを実装するだけで、既存のWebアプリケーションをさくさくっとWebSocketに対応させることができます。

これまで利用してきたHTTPベースのWebアプリケーションを同居させることができたり、同じModelをWebSocketControllerからも利用することができるなど、相互運用性が高いところもポイントです。

環境

Play framework

バージョン1.2以降

ブラウザ

最近の * Google Chrome * Safari * Mobile Safari Mobile Safariというところがポイントで、実はiPhone/iPad/iPod touchでもWebSocketが使えます。

実装例

双方向通信のイメージが湧くように、WebSocketを利用してWebベースのechoサーバを実装してみます。 仕様は以下のようにします。

  1. テストページから、サーバにメッセージを送信できる
  2. 送信されたメッセージが、サーバからそのまま返送される
  3. 返送されたメッセージがページ内に表示される

View

まず、Viewを作成します。

app/views/Echo/demo.html

id=whatのinput要素にメッセージを入力して、id=sayのボタンをクリックするとメッセージをWebSocket経由でサーバに送信します。 id=messagesのdiv要素に、全メッセージが表示されます。

このコードで@@{ /** */ }となっている部分は、WebSocketの接続先の指定です。
このViewがHTMLとして出力される時には、conf/routseのルート定義に基づいて、

のように置換えられます。

また、

は、sendの引数に渡した文字列をWebSocket経由で送信します。

は、WebSocket経由でサーバからメッセージを受け取る度に実行されます。

がサーバから送信されたメッセージです。

Integration Test

仕様1〜3のテキトウなテストを書きます。

今回はWebSocketというブラウザに依存する機能を通したテストなので、Integration TestをPlayのSeleniumテストケースを使います。

先ほど作成したViewを見ながら、
test/Application.test.htmlに以下の内容を追記してください。

このテストケースでは、

  • /echoを開いた時に、エラーが発生していないこと
  • input要素にメッセージを入力して送信ボタンをクリックすると、しばらく後にメッセージがページ内に表示されること

を検証しています。

2つめのテストでは、メッセージがWebSocketを経由してサーバに送信され、サーバがそれを送り返してページに表示される、ということを期待しています。

作成したテストケースは、

から実行できます。

WebSocketController

テストページの表示と、WebSocketでのメッセージのやり取りのためのコントローラを実装します。

Echo.demoがテストページを表示するメソッドです。
render()により描画されるViewは、先ほど作成したapp/views/Echo/demo.htmlです。

Echo.WebSocketEcho.listenがWebSocket経由のメッセージのやり取りを行うメソッドです。
1コネクションあたり1回呼び出され、接続終了までループでメッセージを待ち続けます。
HTTP用のコントローラとは全く実装方法が違いますね。

routes

conf/routesにHTTP, WebSocket用コントローラへのパスを登録します。

前者はhttp://localhost:9000/echoのようなURLへのHTTPリクエストをEcho.demoへ、
後者はws://localhost:9000/echoのようなURLへのWebSocket接続をEcho.WebSocketEcho.listenへルーティングします。

実行例

では早速実行してみましょう。

ブラウザで以下のURLにアクセスすると、デモページが表示されます。

ポート番号はconf/application.confで設定したものです。


[テストページ]1

テストページ

このように、送信したメッセージがWebSocket経由でechoされてページに表示されます。

また、

から、作成したSeleniumテストケースを実行することができます。


[Seleniumテストの実行例]2

Seleniumテストの実行例

このように、ブラウザのWebSocket実装を通したテストもブラウザ上で実行できます。

まとめ

この記事では、Play frameworkのWebSocketサポートについて説明しました。

  • WebSocketはWebブラウザとWebサーバの双方向通信のための規格です。
  • Play frameworkでは、WebSocketControllerを実装するだけで既存のWebアプリに双方向通信機能を後づけできます。
  • Play frameworkでWebSocketを利用したechoサーバとテストページを実装しました

Play frameworkなら、WebSocketを活用したWebアプリがさくっと作れそうな気がしますね!(ΦωΦ)

ソースコードはコチラ(GitHub)