連載
» 2018年06月06日 05時00分 公開

リアクティブプログラミング超入門(4):Java、Scala用マイクロサービスフレームワーク「Lagom」でシンプルなAPI実装 (2/2)

[中村修太,クラスメソッド]
前のページへ 1|2       

Lagomとは

 Lagomとは、リアクティブなマイクロサービス向けに設計されたサーバサイド用フレームワークです。リアクティブなアプリを構築するためのいろいろな機能を持っています。

非同期/ノンブロッキングAPI

 Lagomでは基本的に全て非同期で通信を行います。これによって低レイテンシとなり、外部サービスの影響を受けづらくなります。

イベントソーシングとCQRS

 イベントソーシングとは、「Akka Persistens」(Lagomが使用するPersistensモジュール)の基礎となる設計手法です。この仕組みはエンティティーに対する変化をCRUD(Create、Read、Update、Delete)で表現するのではなく、エンティティーに対するイベントを永続化し、そのイベントを再生することで最新の状態を復元するものです。

 また、このイベントソーシングと相性の良い考え方が「CQRS(Command Query Responsibility Segregation:コマンドクエリ責務分離)」です。

 CQRSでは、「データの読み込み」と「データの書き込み」は明確に違うものだという前提で、データストアへの処理をクエリ(データ読み込み)とコマンド(データ書き込み)に分けます。通常、コマンドは処理の成功/失敗のみの情報を返します。このコマンドがイベントソーシングにおける「イベント」に当たります。またクエリは、冪等性が保証されなければいけません。

 この仕組みを使うと、データの読み込みと書き込みを明確に分離することが可能になります。Lagomは、これをフレームワーク側でサポートしています。

サーキットブレーカー(circuit breaker)

 システムに障害は付きものです。重要なのは「いかに障害を小さくとどめて素早く復旧できるか」にあります。

 サーキットブレーカーとは、障害が発生したサービスをシステムから分離させることでシステム全体を止めずに運用を続けることができる機能です。

 Lagomでは、サーキットブレーカーで下記3つの状態を持ちます。

  • close:サーキットブレーカーが閉じた状態。問題なく通信可能な状態
  • open:サーキットブレーカーが開いた状態。サービスに問題があり、通信不可能。この状態から一定時間経過するとhalf-openに遷移する
  • half-open:サービス復旧を行っている状態。成功すればcloseになり、失敗すればopenになる

 このサーキットブレーカーの仕組みは簡単に使えます。タイムアウト時間やリトライ回数など、サービスごとに細かく設定することが可能です。

その他

 これら以外に、Lagomでは簡単にサービスを実行できる開発環境と「ConductR」による管理機能を持っています。また、デフォルトのデータストアとして組み込みの「Apache Cassandra」がバンドルされています。

 APIが提供されているプログラミング言語は「Java」と「Scala」です。

Lagomのインストールとサンプルの作成

 次に、Lagomを実際にインストールしてアプリを作成してみましょう。

 まずはここへアクセスし、プロジェクト名を指定して「Project作成」ボタンをクリックします。

Lagomアプリ作成画面

 プロジェクトをダウンロードしたらsbtコマンドで起動できます。

% cd path/your/project/lagom-scala-sbt
% ./sbt runAll

 アプリが起動したら、「http://localhost:9000/api/hello/World」にブラウザからアクセスしてみてください。「Hello, World!」と表示されるはずです。

 curlコマンドでも試してみましょう。

% curl http://localhost:9000/api/hello/Taro
Hello, Taro!

 POSTメソッドで下記のようにすれば、データが登録されます。

% curl -X POST -d '{"message":"Hi"}' http://localhost:9000/api/hello/Hanako
 
#GET
% curl http://localhost:9000/api/hello/Hanako
Hi, Hanako!

サンプルのソース説明

 サンプルプロジェクトは、4つのサブプロジェクトで構成されます。

  • hello-lagom-api
  • hello-lagom-impl
  • hello-lagom-stream-api
  • hello-lagom-stream-impl

 hello-lagom-apiとhello-lagom-implがサービスのセットになっており、hello-lagom-apiがサービス定義、hello-lagom-implがサービス実装です。hello-lagom-stream-apiとhello-lagom-stream-implはWebSocketを使用したサンプルです。

 では、hello-lagom-apiの「HellolagomService」を見てみましょう。hello-lagom-apiプロジェクトの方では、サービスインタフェースの定義と、エンドポイントとのひも付けを行います。

 例えばサンプルのHellolagomServiceでは、下記のようにpathCallでAPIのパスと関数を指定します。ここではGETで/api/hello/を指定したときにhelloメソッドを実行するようにしています。

//サンプルを少し編集
override final def descriptor = {
  import Service._
  named("hello-lagom")
    .withCalls(
      pathCall("/api/hello/:id", hello _)
    )
    .withAutoAcl(true)
}

 helloメソッドは、ここでは抽象メソッドとして記述されています。サービス用メソッドはServiceCall型を返すメソッドで、引数としてidを受け取り、型パラメーターはリクエスト型、レスポンス型を指定します。

/**
  * Example: curl http://localhost:9000/api/hello/Alice
  */
def hello(id: String): ServiceCall[NotUsed, String]

 ここではリクエストパラメーターを受け取らないので「NotUsed」です。レスポンスは「String」となっています。

 次に、hello-lagom-apiの実装であるhello-lagom-implを見てみましょう。hello-lagom-implの「HellolagomServiceImpl」では、hello-lagom-apiのHellolagomServiceトレイトを実装し、PersistentEntityRegistry(データ永続化用クラス)を持っています。

//サンプルを少し編集
class HellolagomServiceImpl(persistentEntityRegistry: PersistentEntityRegistry) extends HellolagomService {
  override def hello(id: String) = ServiceCall { _ =>
    val ref = persistentEntityRegistry.refFor[HellolagomEntity](id)
    ref.ask(Hello(id))
  }
}

 helloメソッドではストレージからidをキーにしてエンティティー(PersistentEntityRef)を探し、その結果を返します。

※デフォルトでは、組み込み用Cassandraを永続化に使用しています

APIを追加してみる

 試しに、APIを追加してみましょう。最初に、hello-lagom-apiのHellolagomServiceに抽象メソッドを追加します。

def myApi(id: String): ServiceCall[NotUsed, String]

 次に、descriptorで上記メソッドと追加するパスをひも付けましょう。

override final def descriptor = {
  import Service._
  named("hello-lagom")
    .withCalls(
      pathCall("/api/hello/:id", hello _),
      pathCall("/api/myApi/:id", myApi _)
    )
    .withAutoAcl(true)
}

 hello-lagom-implのHellolagomServiceImplでmyApiメソッドを実装します。

override def myApi(id: String) = ServiceCall { _ =>
    Future{"myApi id = " + id}
}

 ソースの変更は自動でリロードされるので、そのまま下記コマンドを実行してみましょう。追加したAPIが動作しています。

% curl http://localhost:49848/api/myApi/Foo
myApi id = Foo

 以上がLagomにおけるシンプルなAPI実装の基本です。

次回はストリーミングデータ処理フレームワーク「Apache Spark」について

 今回はマイクロサービス向けフレームワーク「Lagom」の基礎について解説しました。

 このフレームワークはマイクロサービス開発を容易にするための機能を多く持っています。本稿では紹介しませんでしたが、サーキットブレーカーやクラスタリング設定も可能になっているので、興味のある方は公式ドキュメントをご確認ください。

 次回は、Lightbend Platformの構成要素の1つ、ストリーミングデータ処理フレームワーク「Apache Spark」について解説する予定です。

著者紹介

中村修太(なかむら しゅうた)

中村修太

クラスメソッド勤務の新しもの好きプログラマーです。数年前に東京から山口県に引っ越し、現在もリモート勤務しています。最近の趣味は空手とぬか漬け作り。


前のページへ 1|2       

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。