リアルタイムBaaS「GoInstant」の概要

はじめに

レッドオーシャン化するBaaS市場

昨年より国内でも盛り上がりを見せつつあるBaaS(Backend as a Service)ですが、グローバルでは昨年だけでも Parse.com のFacebookによる買収StackMob の PayPal による買収とその後のサービス終了のアナウンスなど、サービスベンダー統廃合の波が押し寄せています。GoogleMicrosoftSalesforce.com、そして Amazon などの著名なクラウドベンダーが揃ってこの分野に対して食指を伸ばしてきているのも、すでにBaaSはレッドオーシャンになりつつあるということを示唆しています。

このような中で、残されたBaaSベンダーは、それぞれ自らが生き残る市場を求めて方針をシフトさせてきています。

現在もっとも顕著な動きは、これまでコンシューマ向けのモバイル開発者をターゲットとしていたのを、次第にエンタープライズをターゲットとするベンダーが増えてきたということです。

そして、もう一つ特筆すべき動きとして、これまでの全方位的なバックエンドを受け持つのではなく、ある機能にフォーカスしたサービスを行うBaaSが出てきたということです。この中でも特にリアルタイム・メッセージングを実現するためのBaaSが最近注目を浴びています。

重要性を増す「リアルタイム」

リアルタイム・メッセージングは、古くからチャットやメッセンジャー、オンラインゲームといったサービスで利用されてきましたが、一般的な従来型のWebアプリではクライアントリクエスト/サーバレスポンスによる通信パターンが主流で、あまり普及しているとは言えませんでした。

しかしながら、昨今のスマートデバイスの隆盛と、それに伴なってクライアント端末側に高いエクスペリエンスを要求するアプリケーションが増えてきたこともあり、サーバの状態をリアルタイムに複数のクライアント端末に通知する必要性が次第に高まってきています。

こうしたリアルタイム・メッセージングの実現のためには、WebSocketや非同期処理といった技術を利用する必要がありますが、インフラ構成としてもアプリケーション開発者としても、最初から構築するのはなかなか骨が折れる作業です。しかもその上でスケーラビリティを担保するのはかなりの職人芸が必要になります。

GoInstantとは

本記事で紹介するGoInstantは、このようなリアルタイム・メッセージングのバックエンドインフラをサービス開発者に代わって実現してくれるサービスです。

GoInstantでは、BaaSで一般的に求められるクラウド上でのデータストレージ機能に加え、複数のユーザ間でリアルタイムにデータ同期を行う機能を提供しています。さらにPub/subベースのメッセージ基盤を備えており、デバイスやユーザをまたがった双方向のコミュニケーションに活用できます。

なおGoInstantは、2012年7月にすでにSalesforce.comによって7000万ドルで買収されていますが、同社によって買収されたHerokuと同様に、Salesforceとはサービス的に独立した子会社として運営されている模様です。

使い方

サインアップ

GoInstantには無償利用できる枠(100同時ユーザ、2GBストレージ上限)が用意されているため、サインアップしてすぐ利用を開始することができます。

アプリケーション作成

取得したアカウントでGoInstantにログインするとダッシュボード画面が開きます。まずは Create App ボタンを押して新規のアプリケーションを作成します。アプリケーションを作成すると、Connect URL の欄にURLが表示されます。このURLが次のJavaScriptを作成する際に必要になります。

GoInstant.jpg

HTMLとJavaScriptコードの記述

続いて GoInstant のサービスを呼び出すためのHTMLファイルとJavaScriptコードを作成します。

<!DOCTYPE html>
<html>
  <head>
    <script src="//cdn.goinstant.net/v1/platform.min.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
    <script>
var url = "https://goinstant.net/9cdd2d926d23/helloworld";
var conn, room, Messages;

$(init);

// コネクションの初期化とキーオブジェクトの取得
function init() {
  goinstant.connect(url)
    .then(function(result) {
      conn = result.connection;
      room = result.rooms[0];
      Messages = room.key('messages');
    })
    .then(queryMessages)
    .then(watchMessage)
    .catch(function(err) {
      console.error(err);
    });
  handleEvents();
}

// サーバから最新のメッセージ一覧を取得
function queryMessages() {
  var yesterday = Date.now() - 24*60*60*1000;
  return Messages.query({ 
    timestamp: { $gte : yesterday }
  }, {
    sort: { timestamp: 'desc' },
    limit: 10
  })
  .execute()
  .then(function(results) {
    results = results.reverse();
    $.each(results, function(i, result) {
      appendMessageToList(result.value);
    });
  });
}

// テキスト投稿のイベントを処理
function handleEvents() {
  $("#postBtn").on('click', function() {
    Messages.add({
      text: $("#messageText").val(),
      timestamp: Date.now()
    });
  });
}

// メッセージキーに対するデータ追加の通知をハンドルする
function watchMessage() {
  Messages.on('add', { local: true }, function(message) {
    appendMessageToList(message);
  });
}

// リストにメッセージを表示追加
function appendMessageToList(message) {
  var messageListEl = $('#messages');
  while (messageListEl.children().size() >= 10) {
    messageListEl.children(":last-child").remove();
  }
  $('<li>').text(message.text).prependTo(messageListEl);
}

    </script>
  </head>
  <body>
    <input type="text" id="messageText">
    <button id="postBtn">Post</button>
    <ul id="messages"></ul>
  </body>
</html>

以上は、GoInstantが提供するストレージを利用した、テキスト投稿サービスの例です。バックエンドのプログラムを書かなくてもHTML+JavaScriptのみでこのようなサービスが作成できます。

上記のスクリプトでは、ストレージ内のメッセージデータのクエリ及びデータの追加を行っていますが、特に注目していただきたいのは、watchMessage() 内でサーバ側のストレージへのメッセージ追加のイベントを受け取って処理している点です。

ブラウザを2つ立ち上げて同時にページにアクセスすると分かりますが、一方で投稿したテキストは、即座に他方のブラウザに通知されて、新規メッセージがリスト内に表示されます。

helloworld.gif

特徴

データストレージ

GoInstantでは、ストレージは階層的なツリー構造で提供されており、キーを介して各ノードにアクセスできるようになっています。先程のテキスト統合アプリを例に取ると、メッセージレコードもそれらを格納しているコレクションも、すべて一意のキーが与えられることになります。

階層構造のストレージのルートはルームと呼ばれる単位で管理されています。ルームには接続している参加者のリストが格納されており、ここで参加者を管理したり、メッセージの配信先を制限することができます。

// コレクション
var Message = room.key('messages');
// コレクション内のレコード
var message1 = Message.key('id-1453ab8c1c4-000');
// ルームからのパスで指定することも可能
// var message1 = room.key('messages/id-1453ab8c1c4-000')

/* 1) レコードの内容を取得(コールバック関数での呼び出し)*/
message1.get(function(err, record) {
  // ...
});

/* 2) レコードの内容を取得(Promise形式)*/
message1.get().then(function(record) {
  // ...
}).catch(function(err) {
  // エラー処理
});

後で述べるように、ルーム及びそれぞれのキーに対して、細かいアクセス制御の設定をすることが可能です。

認証

ソーシャルログイン

GoInstantは、FacebookTwitterといった外部アイデンティティプロバイダを利用する、いわゆるソーシャルログインに対応しています。現在サポートされているプロバイダは上記の他にGoogle, Salesforce, GitHubなどがあります。

JavaScript開発者は、特に連携のためのやりとりを気にする必要はなく、 connection.loginUrl(providerName) でプロバイダへのログインURLを取得し、画面をリダイレクトするだけで大丈夫です。

なお、連携するプロバイダについては、あらかじめOAuthのclient_idおよびclient_secretなどを管理設定ダッシュボード画面に登録する必要があります。

JSON Web Token によるアサーション

しかしながら、GoInstantがこういった外部のアイデンティティプロバイダを利用したソーシャルログインに対応したのは実はごく最近で、それまではJSON Web Token(JWT)を用いたアサーションを外部アプリケーションに発行してもらい、それを受け取ってユーザを認証していました。現在も引き続きJWTを利用してカスタムで認証を行うこともできます。

GoInstantが他のBaaSと比べて特徴的なのは、自分自身ではユーザ認証のためのレポジトリを持っていない、ということです。多くのBaaSでは自前でユーザレポジトリを管理し、ユーザ名・パスワードなどのログイン機能を持っていたりしますが、GoInstantでは認証結果を外部プロバイダor外部アプリからアサーションという形で受け取るフェデレーションが前提となっています。このため、既に独自のユーザ空間を持っているWebアプリやWebサイトであっても、プラットフォーム間のユーザ管理の違いに頭を悩ませることなく利用できるようになっています。

アクセスコントロール

BaaSにおいては、エンドユーザから直接データストレージへのアクセスを許すことになるため、データのアクセスコントロールを設定できることは最重要です。また、そのアクセスコントロールのポリシーをどれだけ細かい粒度で設定できるか、ということは、そのプラットフォーム上で利用できるアプリケーションの多彩さを決定づけることになります。

GoInstantでは、アクセス主体をユーザおよびグループ単位で指定できるようになっており、対象のリソースはルームはもちろん、それぞれのキーレベルについても指定可能です。許可する操作についてもかなり細かく(read/writeだけでなくget/set/add/removeとそれらのイベントに対するアクセスなど)指定できます。

なお、先にも記載したとおり、GoInstant内にはユーザレポジトリは存在しないため、ユーザIDやグループなどの情報は外部のプロバイダが利用しているものをそのまま利用するか、外部アプリケーションがJWTのアサーションに属性情報として渡してやる形になります (例:GitHubでログインした場合はユーザIDは github:23387 のような形になる)

これらのアクセスコントロール情報を指定するACLは、JSON形式で記述し、管理ダッシュボードから設定することができます。以下はその例のうちの1つです。

{
  "$room": {
    "#join": { "users": ["*"] },
    "shoppingcart": {
      "#get": { "groups": ["viewers"] },
      "secret": {
        "#get" {
          "users": ["15"],
          "groups": []
        }
      }
    }
  },
  "#connect": { "users": ["*"] }
}

WebRTC

GoInstantは、今年の初めにWebRTCへの対応を発表しました

もちろん、WebRTCのバックエンドを提供しているサービスは他にもあります(国内だとSkyway WebRTCなどが有名です)が、リアルタイム・メッセージングに関わるプラットフォームを包括的に提供しようという意志を感じますし、次世代のコミュニケーションインフラとしての地位を狙いつつあるようにも見えます。

GoAngular

GoInstantが提供するリアルタイムデータ同期の仕組みは、双方向データバインディングを提供するJavaScriptフレームワークと大変相性が良いため、AngularJSなどと組み合わせることによって威力を発揮します。GoAngularは、GoInstantをAngularJSで利用するための仕組みです。

まとめ

想定されるターゲット

GoInstantは、他の多くのBaaS(Mobile BaaS = MBaaS などとも呼ばれます)とは異なり、モバイルアプリに特化している、というわけではありません。Webサイト/Webアプリに対してGoInstantの提供するJavaScriptを埋め込むだけでリアルタイム・メッセージングのサービスを即座に利用できることを売りとしています。

さらに言うと、特にiOSAndroidなどのネイティブアプリ向けのSDKが用意されているわけではなく、現状では想定もされていない様子です。この辺りはすでにiOS向けのSDKなども用意している競合サービスのFirebaseに少々軍配が上がります。

というわけで、新規のモバイルアプリのバックエンドに利用するというよりは、どちらかというとWebサイトやWebサービスは他のPaaS/IaaSなどのクラウド環境で開発・運用を行った上で、リアルタイム関連の機能のみを外出しして利用するようなケースが一番現実味があるでしょうか。本文中で述べたとおり、自前ではユーザレポジトリを持たずに認証連携をデフォルトとするなど、外部サービスとの共存共栄を重視したサービス・アーキテクチャであることは、このような用途に非常に適していると感じます。

また、サーバプログラムを介さなくても静的Webサイトに組み込めるという特性から、S3、GitHub Pagesなどの静的Webホスティングサービスと組み合わせるのも相性が良さそうです。ブログサービスやニュースサイトにウィジットとして埋め込んで、リアルタイム版DISQUS、のような使い方もあるかもしれません。

参考情報:競合サービス