socket.io が提供してくれているものは何か

現在開発中のシステムにリアルタイムな処理があり、そこで socket.io を使おうかなと思ってて、そういう折にタイムリーにもこの辺りの記事がタイムラインで出てきたのでメモ代わりに自分の意見を残しておく。

blog.jxck.io

qiita.com

socket.io が提供してくれているもの

「ブラウザとサーバ間のプロトコル」という観点で見ると socket.ioWebSocket を基本として繋がらなかった時に XHR Long Pollingpolling といった形式の代替手段を提供してくれるもの、という位置づけ。

一方で「ライブラリ」という観点で見ると socket.io はリアルタイムアプリケーションを作る際に必要になる処理をまとめて実装し、クライアントとサーバ間での EventEmitter として抽象化してくれているもの、という風になる。

もう少し噛み砕いて言うと、 socket.io は WebSocket / Long Polling / Polling をラップした上で、さらに便利なAPIや機能を提供してくれるクライアント・サーバのライブラリ、と言ったら良いだろうか。

socket.io がトランスポートのネゴシエーション以外にどんな面倒事を引き受けてくれるかというと、大体以下の様な感じ。

  • 接続している全クライアントへのブロードキャスト処理
  • クライアント・サーバ間で ping-pong する事によるheartbeat確認
  • 接続が切れた時のクライアントの再接続処理
  • ルーム/ネームスペースによるコネクションの管理
  • 認可処理
  • 到達確認

この手の「大概リアルタイムアプリ作るとき必要になるでしょ」的な処理を socket.io が勝手に用意してくれている。 Simple と Easy の違いで言うと、 Easy な API を提供してくれるものだ。

あと細かく言うと socket.ioWebSocket から Long Polling / Polling の代替手段を提供する時に一回一回繋げるかどうか試しながら fallback するのではなく、『一旦全部繋いでみて、繋がったらその中から一番いいやつを採用する』という方式をとっている。これは初期接続の速度を速めるために採用した仕組みだったりする。

逆に言うと、 WebSocket でリアルタイムアプリ作るなら上述したような処理をクライアント・サーバで書く必要がある。

なので、 socket.io をやめて WebSocket だけで作るのもいいけど、 WebSocket は Simple な API であり、色々他にも必要な処理はある。もちろんそこまで難しいものでも無いので自分で書いても問題ないとは思うが、今開発中のプロダクトではそこまでする気にならないし、後述する『 WebSocket 繋がらない問題』もあるので socket.io を採用することにしている。

WebSocket 繋がらない問題

結論から言ってしまうと、WebSocketはWebSocket Secureにしたってつながらないこともある。なんで繋がらないのかはこの記事が詳しい。

qiita.com

ただし、それがどの程度の割合で繋がってて、どれ位のユーザーはつながらないのかというデータを僕含めて開発者はあまり持ってない。

前に WebSocket (not socket.io) 使ったゲームを作ってた時はモバイル向けでB2Cのアプリという事もあってか途中にproxyを挟まないからか、数万単位のユーザーがプレイしても接続不良等の問題は顕著になってなかった(掲示板などで意見収集をしてたが、繋がらないとかそういう声はなかった)。

ただ開発者が欲しいのはこういう"話"じゃなくて、アクセスログレベルで繋がってるかどうかの割合、繋がってるんだとしたらどれ位の期間維持できているのかという"指標になりうる値"だと思うので、今後開発する際はその辺りにも気を配りたい。

つながらないとした時の代替手段

単純に Server からの push としてみると WebSocket じゃなくても他に方法はある。 Server Sent Events がまさにそのケースにマッチする。

一方で、 WebSocket は push の機能だけじゃなく、双方向で通信が可能になるものなので、一方通行でサーバからしか送信しない push とは少し趣が異なる。WebSocketを使わずに双方向で通信するような処理をしたい時は Server Sent Events で実現する受信の機能と XHR での送信の機能を併用するような形を取る。

つまりはコネクションを2つ併用する形になる。ネットワークレイヤから見るとTCP接続2本貼ってて無駄はあるが、代替手段なのでしょうがない。

個人的な思い

このツイートで言いたかったことは終わりなんだけど、あんまりこの手のリアルタイムアプリ向けのライブラリが Node.js 以外でそこまで発展していないのかもしれない。

ただ、 Rails に最近入った ActionCable を見てみると、 上に書いたような socket.io が機能としてやってくれることは大体やっていたし、今はやってないけど多分すぐにトランスポート層ネゴシエーション機能も入ると思う。

また Elixir の phoenix にはトランスポート層ネゴシエーションまでやってるライブラリがあると聞いたので、この層を解決するようなフレームワークは増えている。それも含めて積極的に使って行ったほうが良いと思う。

2016年になってウェブの世界でもプロトコルは進化していて、より良いプロトコルがあるなら使った方がいいし、実際にユーザーがちゃんと使えているのかはモニタリングしておきたい。一方で互換性をちゃんと保つことも必要で、多少無駄があるとしても繋がる/使えるという状況は保つようにしていたい。