トコロテンの日記

自分の活動内容や普段考えていることをアウトプットするためのブログです。ITに関わる話がメインであり、開発、競技プログラミング、気に入った技術などの話が多くなります。

Treasure2020 3日目

f:id:tokoroten_lab:20200806220543j:plain

はじめに

こんにちは。トコロテンです。

最近、夏だからといっても暑すぎませんか。 そう思いながら気象庁のページを見たら下の図があって目ン玉飛び出ました。

f:id:tokoroten_lab:20200817085101p:plain
2020/08/16日最高気温(気象庁より引用)

これは暑いですね。 僕の体力が落ちただけかなと少し思っていまいしたが、客観的に暑そうです。 コンビニ行くだけでも汗だくになるので一回お店行った時に買い溜めするようになりました。

本当に、熱中症には十分お気をつけください。

前回の記事に続き、Treasure2020の3日目に学んだことと感想をテキストに起こします。

そして新たなプロトコルへ…

3日目も2日目と同じくバックエンドの講義でした。 ただし、今回はHTTPメインではなく、WebSocketとWebRTCがメインの内容でした。 WebRTCは名前しか知らない状態から始まり、接続プロトコルを学んでちょっと実装をするとこまでしたので自分にかなり多くの学びを得ることができました。

講義で学んだことは以下の通りです。

  • WebSocketの概要
  • HTTPとWebSocketの違い
  • スケーリングの話
  • WebRTCの概要

WebSocketの概要

Webベースでオンラインゲーム作ろうとしたことがある方なら必ず一度は調べるであろうWebSocket。 僕も高校の文化祭で展示するオンラインゲームを作る時にWebSocketを使いました。

WebSocketは、低コストで双方向のリアルタイム通信が行える素敵なプロトコルです。 WebSocketという名前にもあるように、実態はただのTCPを用いたソケット通信です(それはそう)。 TCPのコネクションを張って通信路上で任意の通信が行えるので何でも作れます。 例えば、一般的なチャットからマルチプレイ対応の格ゲーまで様々な用途が存在します。

HTTPとWebSocketの違い

新たに登場したWebSocketはHTTPとどのように違うのでしょうか。 細かい違いを挙げていくと無限にありますが、大まかに分けると以下の2つが決定的な違いだと思います。

  • ステートレス(HTTP)とステートフル(WebSocket)
  • Pull(HTTP)とPush(WebSocket)

ステートレス(HTTP)とステートフル(WebSocket)

ステートレスとステートフル、名前からステートがあるかないかといった違いがあるということはわかるのですが、ステートって一体なんでしょうか。

自分は、サーバに保存されるクライアントとのセッション情報のようなものだと解釈しています。 もっとしっかりした定義や良い解釈があれば教えて頂けると嬉しいです。

ステートレス(HTTP)

HTTPでは、基本的にクライアントから1回リクエストを投げるとサーバがそのリクエストに対するレスポンスを返して1つの処理が完了します。 この手順には、クライアントとのセッション情報のようなものを利用しないため、ステートレスであると言えます。

ステートフル(WebSocket)

WebSocketでは、コネクションを確立した後、そのコネクションを使いまわし、クライアント毎にデータを保存しておくため、ステートフルであると言えます。

Pull(HTTP)とPush(WebSocket)

PullとPushって方向があると思うんですが、これってサーバ側から見た場合なのかクライアント側から見た場合なのかどちらなんでしょう。

これは、サーバ側から見た場合になります。

Pull(HTTP)

Pullは、クライアントからサーバにリクエストを送ってそのレスポンスを返すような挙動を指します。 HTTPは、この方法で通信を行うため、Pull型であると言えます。 クライアント駆動(クライアント側でのイベント発火がメッセージングのトリガになる)と考えることができます。

Push(WebSocket)

Pushは、サーバからクライアントにメッセージを送る(クライアントからのリクエストはいらない)ような挙動を指します。 WebSocketは、この方法で通信を行うこともできるため、Pushが可能です。 ただし、WebSocketは双方向の通信が可能なため、もちろんPullのような動作も可能です。 これによって、基本的にHTTPではクライアント駆動しかできませんでしたが、WebSocketではサーバ駆動(サーバ側でのイベント発火がメッセージングのトリガになる)が可能になったと考えることができます。

ユースケース

始めに自分の結論を述べると、ステートを持つ必要があったりリアルタイム性がほしい場合はWebSocketを利用し、それ以外の場合は実装のしやすさからHTTPを用いれば良いと思います。

HTTP

ステートレスという性質から冪等性があるため、コンテンツのキャッシュを行うのに向いている気がします。 また、コネクションを維持する必要がないため、リアルタイム通信を行わないのであれば無駄なくサーバとのやり取りを行うことができることや、ステートを管理する必要がないため、ステートフルなものと比べてロジックが簡単になります。

WebSocket

WebSocketの概要でも述べた通り、リアルタイム性の必要なサービスに向いています。 また、Webアプリのクライアント間の同期の面からサーバ駆動にしたい場合は多く、そのような場合にはWebSocketが向いていると思います。 例えば、既に挙げたオンラインゲームやチャットがその典型例です。

スケーリングの話

WebSocketはサーバがクライアント毎にステートを管理して通信を行うため、負荷分散等でスケーリングをする際にはちょっと一工夫必要になります。

例えば、WebSocketを用いて複数人でチャットができるサービスがあったとします。

元々、サーバが1台(S1)だけであったものを2台(S1とS2)に増やすことを考えます。

この場合、各クライアントがS1またはS2のどちらかに接続することになりますが、S1はS2に接続しているクライアントの情報を知らず、S2はS1に接続しているクライアントの情報を知らないといった状態になります。 この状態では、各クライアントのチャットのメッセージを全クライアントに共有することができません。

これを解決するには、S1とS2の間にもコネクションを張ります。 そして、S1が知らないクライアント宛への通信はS2に委任し、S2が知らないクライアント宛への通信はS1に委任します。 委任する際には、S1とS2の間に張ったコネクションを通して情報を交換すれば良いです。

このようにして、WebSocketを利用するサーバのスケーリングを行うことができます。

WebRTC

ちょっとここを詳しく書く時間が無いため、参考にしたページを示します。 以下のMDNのドキュメントに全てが書かれています。

developer.mozilla.org

講義では、主にWebRTCの接続プロトコルについて学習しました。 接続プロトコルは、以下のドキュメントで確認することができます。

developer.mozilla.org

さいごに

これまで全く触ったことのない技術(WebRTC)に触れてめちゃくちゃ興奮してました。 WebRTCに関するMDNのドキュメントが綺麗に整備されていたおかげでスムーズに学習することができました。

自分がある程度知っているものについて深く考えて理解を深めるのと自分が全く知らないものについて学習して理解するのでは、頭の使い方が全然違うと感じます。 これまでの2日間が前者だったため、後者に該当する今回の内容は良い刺激になりました。