あのちっく小屋

ブラウザへのリアルタイム送信をやりたいとき、FirebaseとPusherどちらを使うか。

2022.09.11
あのちっく

チャットシステムを作っていて、「新規メッセージが投稿された!」というイベントを、多数のユーザーに知らせるような仕組みが欲しい。 この記事ではこのような仕組みを実装するにあってFirebaseあるいはPusherを使う場合のそれぞれの長所短所、その他留意点について記述する。

やりたい事

基本的にはユーザーへの通知なのだけれど、実は1つのソリューションだけでは解決できない気がする。というのも、ユーザーへの通知と一言に言っても

  • 1.Webアプリを開き、チャット画面を開いている状態の人にイベントを送信し、新しい投稿を表示する。
  • 2.Webアプリを開いていないユーザーへWeb Pushなどで通知を送る(プッシュ通知)

の2つが欲しい気がする。今回は1をMust、2をWantぐらいで考えている。とはいえ、プッシュ通知の仕組みも使えると嬉しい。

Firebase

FirebaseはMBaaSと呼ばれるもので、「モバイルアプリを作るためのバックエンドシステムを一通り揃えたサービス」である。サーバレス関数・ファイルストレージ・ドキュメント指向DB等がある。

Firebase Cloud Firestore(Firestore)

Firebase Cloud Firestoreはドキュメント指向のリアルタイムDBである。 データが追加・更新・削除すると、そのコレクションおよびドキュメントを購読しているすべてのブラウザにリアルタイムで更新イベントが送信される。

Firebase Realtime Databaseとの比較

Firebaseには Firestoreと似た性質のFirebase Realtime Databaseというものが存在する。これもFirestoreと同様、ドキュメント指向のリアルタイムDBだが、仕様がところどころFirestoreと異なる。要点だけ書くと

  • Realtime Databaseのほうがレイテンシが低く、リアルタイム性能が良い。
  • Firestoreはマルチリージョンに対応している
  • スケーラビリティはFirestoreのほうが上
    • RealtimeDatabaseは最大同時接続20万件、秒間1000件の書き込みまで
    • Firestoreは最大同時接続100万件、秒間10000件の書き込みまで
  • 料金はFirestoreのほうが安い

という感じ。Firestoreのほうが後発なため利点が多い。 より低レイテンシを求めるならRealtimeDatabaseになるが、今回はmsレベルのシビアなレイテンシを求めているわけではないのでFirestoreで十分。

認証・認可はFirebase Authenticationで出来る

「チャンネルについてのイベントは、そのグループのユーザのみが受けられるようにしたい」ということがあると思う。これはFirebase Authenticationでユーザー認証がされていれば出来る。 Firestoreは、ルール定義を作成することが出来、「ログインユーザーのメタ情報がxxx」の場合のみ閲覧可能というようなルールを作っておくと良さそうだ。

Firebase Cloud Messaging(FCM)

あまり知られていないが、FirebaseにはFirebase Cloud Messagingという通知機能を提供するサービスがある。 ServiceWorkerを使ったWebPushにも対応していて、なかなか使いやすい。 不思議なことに、この Firebase Cloud Messagingは、完全に無料で利用できる おそらく利用制限はあるだろうが、料金が発生しないというのは逆に不安になる。 また、利用制限の他にも仕様として1アプリにつき登録できるトピックは2000までやデバイスの最大同時接続2500台などの制約がある。 この制約は実装の工夫でどうにでもなりそうな気はするが、気をつけないといけない所ではある。

(というか、無料のサービスを信頼していいものだろうか...)

ともかく、Firebaseを使えばFirestoreとFCMを使うことで、ブラウザへのリアルタイム送信と、ユーザーのデバイスへのプッシュ通知が実現できそうだ。

Pusher

Pusherはリアルタイム送信に関するソリューションのみを提供するクラウドサービスだ。

Pusherのサービスは、サーバーからクライアントアプリへの送信を実現するための[Channels]と デバイスへのプッシュ通知を実現するための[Beams]が存在する。 どちらも今回やりたい事に合致していそうだ。

Pusher Channels

Pusher Channelsは、いわゆるpub/subの仕組みを提供する。

const channel = pusher.subscribe('雑談'); channel.bind('my-event', function(data) { setMessage(data.message) });

こんな感じのコードで、"雑談"トピックを購読しておくと、雑談トピックのイベントを受け取ることが出来る。

イベントのpublishの仕方は

pusher.trigger("雑談", { "message": "こんにちは" });

これだけ。とても簡単。

ユーザー認証とプレイベートチャネルがある

当然ではあるが、ユーザー認証しないとsubscribe出来ないようにすることも出来る。 その仕様は少し変わっていて、「トピック名の頭にprivate-をつけるとプライベートチャンネルとして扱われる」ということらしい。

細かい購読権限管理は出来ない

「ログインしたうちの一部のユーザーのみが購読できるチャネル」を実現する機能はなさそう。 トピック名を一部のユーザーしか知れないような仕組みにするか、イベントにはプライベートな情報は含めないようにしたほうが良さそう。

FirebaseとPusherの比較

料金比較

料金体系が異なるので、2つのケースで見積もってみる。 月額費用を算出していく。

今回はpub/sub機能のみの比較。プッシュ通知については考えてない。

A . 1日あたり40万回メッセージが投稿される、1つの投稿を4人がサブスクライブしている場合

pub/sub比が0.25のケース。小規模チーム。

Pusher→無料(Sandboxプランの範囲に収まる。) ただし、同時接続は100に限定される。

Firestore→$48.42 書き込みが38万/日($0.684) 読み取りが155万/日($0.93) 無料枠超過分で計算、ネットワーク帯域・ストレージの利用については軽微なので計算に含めない

B . 1日あたり20万回メッセージが投稿される、1つの投稿を199人がサブスクライブしている場合

pub/sub比が0.005と、ちょっとしたエンタープライズ規模。

Pusher→$699 Growthプランなので、同時接続は15,000まで。

Firestore→$725.22 書き込みが 18万/日($0.324) 読み取りが3975万/日($23.85) 無料枠超過分で計算、ネットワーク帯域・ストレージの利用については軽微なので計算に含めない

あれ、意外といい勝負になった。

その他比較

Firebase

いいところ

  • Firestoreは汎用DBとして使える
    • 通知以外にも便利に使えそう
  • 使ってる人が多いので情報も多い
  • ルールによってユーザーごとの購読制限がかけられる
  • 同時接続制限はほぼ気にしなくて良さそう

悪いところ

  • 結構すぐ無料枠超えそう
  • FCM無料なのが怖い

Pusher

いいところ

  • 無料枠が大きい
  • ユースケースにマッチしているからシンプルな実装で済む
  • ライブラリのインタフェースがシンプル
  • 通知システムも安心して使えそう

悪いところ

  • 同時接続数の制限にかかりそう
    • スタートアッププランにしたけど、なにかに取り上げられて一瞬ユーザー数めちゃ増えたとかに対応するのに無駄にお金かかる。

結論

思ったよりいい勝負になっちゃったけど、今回はPusherを使おうと思う。 料金面ではそこまで大きな違いはなさそうだけど 1日の無料枠という見方をすると、Pusherのほうがお得なので、最初はPusherを使って、サービスのpub/sub比の平均が得られたら考えるのが良さそう。