ヽ(´・肉・`)ノログ

How do we fighting without fighting?

Rails4と非同期通信

まとめ

アプリケーションサーバーにおける非同期通信に関する一般的な話題

Web アプリケーションでの情報の取得について考える.情報元へ「とある条件のものは”あるか”」と毎回問合せて結果を処理しているであろう.これを同期通信と呼ぶ.

チャットなどの頻繁に更新するような Web アプリケーションの場合,毎回問い合わせ直すときのやりとりが負荷になったり面倒だったりするので, 情報元へ「とある条件に”なったら”知らせて」と伝えておき,あとは待ち受ける,非同期通信という方式がよくとられる.

さて Web アプリケーションでの情報の取得について考えてみる. クライアントから App サーバーへ問い合わせがリクエストされると,App サーバーはストレージへ問い合せ,結果を取得し,その結果を加工してクライアントへ返す.

つまり情報の取得はおおまかに以下の 2 つの部分で行われている

  1. クライアント と App サーバー間での情報取得
  2. App サーバーとストレージ (DB など ) 間での情報取得

どちらか片方だけを非同期通信としても,もう片方が非同期通信になっていなければ,処理性能はすぐに頭打ちになってしまう.

つまり,非同期通信を行う場合はこの 2 つの情報取得についての非同期通信を考える必要がある.

クライアントとアプリケーションサーバー間での非同期通信については Websocket や SSE という方式があることが良く知られている.

アプリケーションサーバーとストレージ間での非同期通信についてはどうか. あらかじめ処理を登録しておくと値が追加/削除されたようなタイミングで通知してくれる仕組みがあればうれしい.

アプリケーションサーバーが Rails の場合

具体的に App サーバーが Rails の場合について考えてみる.

Rails がクライアントと非同期通信するには,前述のとおり SSE や Websocket を利用する.SSE の場合は Is it live? が簡潔でわかりやすかった.

それでは Rails がクライアントに伝える「内容」をストレージから取ってくる場合はどうか. 上にあげた Is it live? ではストレージに該当する部分がファイルシステムだったのでのファイルの変更を非同期で検知する FSEvent というのを使って Rails とストレージ間の通信を非同期にしていた.

通常,データは DB から取ってくるであろう.その場合は DB がストレージとなる.DB を対象に非同期通信できるだろうか? 今回調べたところ,RDB である PostgreSQL には listen と notify という非同期通信があることを知った.

これを Rails で利用した記事が Rails 4 Server Sent Events with ActionController::Live and PostgreSQL NOTIFY/LISTEN だ. 文中にある「既に利用しているものだけで非同期通信が実現できないか.そうすることで複雑さを抑えられないか」という気持に共感する.

結論としては,使えるけど,通知には1コネクション必要なので,DBコネクション数が同時接続数の上限になってしまうようだ. コネクションプーリングを使って App サーバーと DB サーバーの同時接続数を抑えている場合などには利用できないであろう.

2014 年 10 月現在においては,DB コネクションの問題があるため,RDB とは別に Redis を利用するサービスに加え, データの保存については RDB,通知については Redis の PUB/SUB を利用するのが現実的な解であろうという結論に達した.

Rails4 で Redis を利用した非同期通信については Rails 4 Streaming API がわかりやすかった.

このエントリーをはてなブックマークに追加