チャットなどリアルタイム更新が必要なスマフォアプリの構成について考えてみた

  • 936
    いいね
  • 0
    コメント

今開発しているPlayer!で、チャット系のリアルタイム更新処理が必要となったので、色々調べています。

※「スマフォアプリ」として共通事項が多いのでそう表記しましたが、基本的にスマフォアプリはiOSアプリとして書いてます。Android・Windows Phoneなどは差異があったり読み替える必要があると思っています。

結論

後半で詳しく書きますが、今のところ以下の結論に至りました。

開発リソースが潤沢で無い場合は、以下の順でシフトしていけば良いのではと思います。
工数が少ない中、欲張って双方向通信取り入れたガタガタになるより、まずはPUSH通知に頼っちゃった方が賢明に思います。

  1. まずはPUSH通知に全て依存
  2. PusherFirebaseなどのサービスに頼って双方向通信処理も併用
  3. wsSocket.IOSignalR + 対応クライアントライブラリなどで自前実装して双方向通信処理も併用

有名どころのアプリは大体、3の方法を取っていました。
(# 他のアプリの調査で後述)

AppleのPUSH通知サービス(APNS)について

こちらにまとめました:
iOSのPUSH通知(APNS)の特徴・ノウハウまとめ(iOS 9まで対応) - Qiita
Stockもはてブも3-400以上いただけてありがたやです( ´・‿・`)

以下で、基本的なリアルタイム更新の要件を満たせると思います。

PUSH通知切られちゃうと動かないのと、 レスポンスタイム的にはやはり双方向通信有利かなと思います。

iOSのSilent Notificationは許可画面が要らない?を見て、確かにと思い検証した結果、確かにその通りでした。
ユーザー体験考慮のためにも、デバッグにハマらないためにも、知っておいた方が良いですね。

  • サイレント通知: バックグラウンド更新が許可されているか否か
    • こちらはデフォルトオンなので、PUSH通知の許可より有効率が高そうですね
  • 通常のPUSH通知: PUSH通知が許可されているか否か

双方向通信

ざっくり、以下の歴史があります。

  • 定期ポーリング
    • 定期的にリクエスト投げてデータ更新
  • ロングポーリング
    • サーバーがリクエスト受けてからデータ更新されるまでレスポンスを遅延させる
  • Server Sent Events
    • ロングポーリング改良版

ここまでがHTTPの規格に沿ってリアルタイム更新を実現する技術です。

今双方向通信と聞くとまず思い浮かぶであろうWebSocketは、HTTPの縛りを外して作られたWeb標準(RFC 6455 / W3C CR)です。

それまでのものと比べて以下のようなメリットがあります。

  • ヘッダが軽量
  • リアルタイム性が高い
  • サーバー負荷が低い

デメリットは以下です。

  • サーバー・クライアントともにWebSocket規格への準拠が必要
    • 特に旧ブラウザ(古いIE・Androidなど)で問題になる
  • 既存の通信機器を通過できない可能性がある

特に前者は、サーバーとスマフォアプリで通信する場合にはまったく困らないですね。

サーバPUSHざっくりまとめの資料が簡潔で分かりやすかったです。

このあたり、調べるとキリがないのですが、今回の要件では、このくらいざっくり理解した上で、性能も採用例も多いWebSocketベースに組めば良いと見なして良いと思います。
(僕はけっこう調べちゃいましたが)

XMPPは?

メッセンジャー系の標準規格というようなイメージでしたが、最近は下火な感じなのでわざわざこれに従わなくて良いと思いました。

その他、参考になった資料

サーバーサイド自前実装の際の選択肢

素のWebSocketライブラリ

一番素直なのは、後述のSocket.ioなどでは無く、純粋なWebSocket仕様に即したライブラリを選定して使うことだと思います。
特に、スマフォアプリの場合は、WebSocket非対応ブラウザ問題が無いので、素のライブラリでも十分いけるかと思います。

参考: WebSocket の導入: ウェブにソケットを実装する - HTML5 Rocks

Socket.io

WebSocket系のライブラリとして一番有名かと思います。
Node.js発祥のリアルタイム通信モジュールです。
純粋なWebSocketモジュールではなく、トランスポート層の1つにWebSocketを利用しているものです。
WebSocket非対応環境の場合はロングポーリング動作に切り替えるなどフォールバックが用意されていたり、リッチなAPI(自動再接続・認証など)がセットになっていたりします。
なので、Socket.ioで組まれたサーバーに接続するクライアントは素のWebSocketクライアントライブラリでは無く、Socket.ioクライアントライブラリである必要があります。

Socket.ioの場合の言語の選択

Socket.ioの場合、本家のNode.js一択だと思います。
Goでも性能出そうだなと思いましたが、まだ歴史が浅いのかこれに関してはまだ劣るようです。

Socket.io vs SignalR

Microsoft系の技術にあまり馴染みの無い場合、SignalRのことはほとんど知らないかもしれませんが、ASP.NET上で動作するライブラリです。
Socket.ioと同様に、純粋なWebSocketモジュールではなく、トランスポート層の1つにWebSocketを利用しています。
海外ではそこそこ盛り上がっているようですが、国内では微妙ですよね(´・ω・`)
Socket.ioに遜色の無いライブラリ(かつそれぞれ特徴あり)なので、検討しても良いと思います。
特にMicrosoft系技術に強い場合は、オススメですヽ(・ω・`)

双方向通信系のサービスは何を選べば良い?

自前実装だと何が困難?

双方向通信系のサービス比較の前にまずこちらです。

  • 単純に技術選定・設計・実装コストがかかる
    • 双方向通信系のサービス以上に色々な言語・ライブラリ・構成など選択肢があるので自信を持って組むのが大変
    • かなり時間かけるか、ノウハウ持った経験者の助けが欲しい
  • 特にスケールアウトが難しい

双方向通信系のサービス比較

シェアではPusher、勢いとGoogleブランド的にはFirebaseですかね。

Pusherは、アーキテクチャー的に、Pusher→クライアントへのPUSHのみで、他は通常のHTTPとなっていて特殊かもしれません。
しかし、「リアルタイム更新が必要なスマフォアプリ」の要件をシンプルに満たしていて良いと感じています。
自前実装にするにしても、この構成かなとイメージしてます。
流行りのマイクロサービスっぽく、APIサーバーとは切り離して、独立して双方向通信機構を開発しやすそうです。

hero_howitworks-d5840af909cfca0b448c6b24fdfdf9af6a95263d79ada6a789607b8f6bc7a6e1.png

Pusherは簡単にGoとSwiftでサンプル組んでみましたが、けっこうシンプルでした。

Firebaseはドキュメントしか読んでないですが、リッチな印象です。

双方向通信系のサービスデメリット

  • ロックインされてしまうかもしれない
    • 実装切り替えることを見据えて、ちゃんと疎結合にすれば大丈夫そう
    • 特にPusherの構成はすり替えしやすそう
  • お金がかかる
    • Pricing | Pusher
    • ただ、自前実装の場合もサーバー代はけっこうかさむはず

iOSアプリの双方向通信実装

ライブラリ選定

webSocket通信を知らないiOSエンジニアが知っておいて損はしない(経験談的な)軽い話が参考になりました。

接続確立・切断のタイミング

こんなフローを実装に落とし込めば良いと思います。

  • アプリ起動時に接続確立し、その後はずっと接続を保つ
    • beginBackgroundTaskWithExpirationHandlerでの、バックグラウンド動作延命措置も入れる
    • オフラインになったりして切断された後の復帰など例外系も考慮
  • アプリが完全に終了したタイミングで切断される
    • この状態ではPUSH通知頼り
  • 接続中は、サーバー側でPUSH通知発行する必要無し

他のアプリの調査

他社製iOSアプリの実装の探り方 - Qiitaに書きましたが、以下の通り4つのうちLINE以外はWebSocket系でした。
Socket.ioのような、WebSocket・ロングポーリングをくるんだライブラリのクライアントライブラリではなく、素のWebSocketライブラリですね。

議論の参考になったもの

「リアルタイム更新が必要なスマフォアプリの構成」についてぐぐって上位に引っかかる、有名どころのやり取りは大体目を通したと思っています。
日本語は技術解説記事などは十分ありましたが、こういった議論についてのものはほぼ見当たらなかったです。

本記事は、技術的な調査 + こういった議論を読んだ上で、僕なりの感触を示したものです。

少しチェックしたものの、不要と判断した情報

  • Stream Programming Guide
    • 上位レイヤーのライブラリが充実しているのでそれ使えば良いと判断
  • あなたにWebSocketは必要ないかも
    • 不安にさせるだけで結局どうすれば良いのか分からない
    • WebSocket系のライブラリや利用例が充実しているから、それ使うのは悪い選択肢じゃないと判断