Play framework 2.xを既存のWebサーバーと連携させる方法、並列処理や双方向通信を行う方法を紹介します。
前回の記事「Play2(+JavaScript)アプリを高速化、最適化する4つのテクニック」では、キャッシュの利用方法や非同期通信を行う手法、クライアントサイドでJavaScriptをうまく扱うテクニックについて紹介しました。
今回はPlay framework 2.x(以下、Play2)を既存のWebサーバーと連携させる方法、並列処理や双方向通信を行う方法を紹介します。
連載第2回記事「Play 2.0のアーキテクチャとディレクトリ構成の基礎知識」で解説をしましたが、Play2では「Netty」というHTTPサーバーを内包しており、それを使用してリクエストを処理します。そのため、Play2の起動ポートを80番に設定すれば通常のWebサーバーと同じようにアクセス可能です。
単純なWebアプリケーションの場合はこれで問題はないのですが、単一サーバーで複数アプリを使用したり、サーバーをクラスタリングしてスケーラブルにしたい場合には、フロントにApacheやnginxなどのHTTPサーバーを使用して、Play2アプリ(Netty)と連携させることもできます。
nginx(エンジンエックス)は、オープンソースのWebサーバーで、2013年時点ではApache、IISに次ぐ使用率を持っています。
HTTP以外にもリバースプロキシの機能を持っており、Proxyサーバーとして他のアプリケーションサーバーと同時に使用されることも多いようです。既存のWebサーバーよりリソースを抑えつつ、高い処理性能を実現できます。
では、nginxをインストールしてPlay2アプリと連携して動かしてみましょう。
まずはnginxをインストールしましょう。ここでは、OS X/Mac OS XでHomebrewを使用している場合を説明します。下記コマンドでnginxをインストールできます。
% brew install nginx
それ以外の環境でnginxをインストールする場合、nginxのコミュニティサイト「InstallJa」のページを参照してインストール方法を確認してみてください。
インストールが完了したら起動してみましょう。
% nginx
上記コマンドを実行し、「http://localhost:8080」にアクセスして、次のような画面が表示されればインストールは完了です。
では、nginxのリバースプロキシ機能を使用してPlayアプリと連携させてみましょう。Homebrewでインストールした場合「/usr/local/etc/nginx」に「nginx.conf」があります。
※設定ファイルの場所が分からない場合、「nginx -t」コマンドを実行すれば、どこにある設定ファイルを使用しているかが分かります
nginx(80番ポートで起動)にアクセスがきたら、Playアプリへフォワードするように指定します。
http { ・ ・ ・ upstream my-backend { server 127.0.0.1:9000; } server { listen 80; server_name localhost; location / { proxy_pass http://my-backend; } ・ ・ ・ }
nginx.confを編集したらnginxを再起動し、Playアプリを起動しましょう。
% nginx -s reload(sudoが必要な場合もあります) % cd /path/rour/gyro % play run
アプリが起動したら、「http://localhost」にアクセスしてみてください。今までと同じく、Playアプリが実行されています。このように、簡単にnginxとPlayアプリが連携できていることが分かります。
Akkaとは、Scala/Javaで非同期処理を実現するためのライブラリで、Scalaの開発元であるTypesafe社が中心となって開発しています。Akkaは軽量な並列処理のためのActorモデルをベースとしており、分散/並列/耐障害性を持ったイベント駆動型アプリケーションを構築できます。
Akkaは「アクターシステム」と呼ばれるコンテナーを持っており、Play2アプリでは、アプリケーション自身が使う特別なアクターシステムが定義されています(※独自のアクターシステムを使用しても問題ありません)。
そして、Play2アプリのアクターシステムを利用するためには、play.api.libs.concurrent.Akkaオブジェクトを利用します。
import akka.actor._ val act = Akka.system.actorOf(Props[MyAct],name="myAct")
なお公式ドキュメントでは、「デフォルトのアクターシステムは、実行するアクターの数が少なく、別のアクターシステムを自分で用意するまでもないような場合に利用するとよい」とあります。こちらも併せてご確認ください。
この章ではPlay2アプリ上でAkkaを使用し、スケジューリング処理を行ってみましょう。
Akkaを利用することで、任意の処理を一定時間ごとに実行したり、指定時間後に1回だけ実行したりすることができます。
以前、アプリ起動時に処理を行うため、いつも使用しているgyroプロジェクトに、GlobalSettingsを継承したGlobalオブジェクトを作成しました。このオブジェクトでAkkaを使用してタスクのスケジューリングを行ってみましょう。
Globalを作成していない場合、appディレクトリ下に「common.scala」という名前のファイルを作成してください。common.scalaでは下記のように記述しましょう。
import play.api._ import play.api.Play.current import scala.concurrent.duration.DurationInt import play.api.libs.concurrent.Akka import play.api.libs.concurrent.Execution.Implicits._ object Global extends GlobalSettings { override def onStart(app: Application) { //↓以前作成したコード Logger.info("Application has started for " + app.mode + " mode.") app.mode.toString match { case "Prod" => Logger.info("Prod mode.") case "Dev" => Logger.info("Dev mode.") case "Test" => Logger.info("test mode.") case _ => Logger.info("unknown mode.") } //5秒後に1回だけ実行 Akka.system.scheduler.scheduleOnce(5 seconds) { println("execute Once") } //10秒ごとに実行 Akka.system.scheduler.schedule(0 seconds, 10 seconds) { println("execute Every 10 seconds") } } override def onStop(app: Application) { Logger.info("Application shutdown...") } }
アプリ起動時(devモードでは初回アクセス時)に実行されるonStart関数では、Akka.system.schedulerを使用して、スケジューリング処理を実行しています。scheduleOnce関数では第1引数の指定時間後に{}内の処理が1回だけ実行され、schedule関数では第1引数時間後に第2引数時間ごとに{}内の処理が実行されます。
上記記述をしたら、アプリを起動してアクセスしてみてください。コンソールにメッセージが表示されます。
なお、「5 seconds」といった特殊な記述は、importしている「scala.concurrent.duration.DurationInt」で暗黙的型変換が行われることによって可能になっています。
次ページでは、AkkaとWebSocketを使ったサンプルを試してみましょう。
Copyright © ITmedia, Inc. All Rights Reserved.