岩本隆史の日記帳(アーカイブ)

はてなダイアリーのサービス終了をうけて移行したものです。更新はしません。

非同期にしたいけれど

Create/Update/Deleteのリクエストに関しては、そのリクエストをキューにしまい、クライアントにはすぐにレスポンスを返した上で(つまり、HTTP Requestの処理に必要なスレッド・プロセスはすぐに解放して)、別プロセス(それもシングルプロセス)でキューにたまったリクエストを順繰りに非同期で処理すべきだ。

Life is beautiful: マルチスレッド・プログラミングの落とし穴、その2

すごくよく分かるんですが、Tatsuさんの下記コメントと同じ疑問が浮かびます。

「私の写真」にいるときのように、データベースの最新の状況を反映しなければならないシーンのケアはどうしても必要なようですね。そうすると同期書き込み(もしくは非同期書き込み後の、対象を指定した同期読み込み)要求はやっぱり用意する必要があるということかな。。。

自分の要求はわかっているのでクライアント上で勝手に更新表示しておくこともできるけど、再表示などで読み込みが発生するときまでに書き込みが反映されている保証はないし。

Life is beautiful: マルチスレッド・プログラミングの落とし穴、その2

ユーザ的には、自分が写真を投稿したら、すくなくとも自分の見ている画面には、投稿結果がすぐ反映されてほしいですよね。「10秒後に反映されているかもしれません」では、不安になってしまう。結局、同期処理にせざるをえないんじゃないかなあ。

Cometを使えば非同期でいけるのかもしれませんが、JavaScriptの使えないUAが排除されてしまいます。同期にすればパフォーマンスが損なわれ、非同期にすればユーザビリティが損なわれ、Cometにすればアクセシビリティが損なわれ、まさにあちらを立てればこちらが立たずですねー。

追記(2008-09-25)

たとえば写真に付いたコメントを表示させる場合、「最新の情報をすぐに」表示するのが良いのが当たり前だが、それが過負荷のためにどうしても不可能になった場合に、

  • 表示するまで15秒かかる
  • 表示はすぐにするが、それは15秒前の状態(投稿されたコメントが反映されるまで15秒かかる)

のどちらがユーザーから見てストレスが少ないか、どちらの状況になるように設計しておくべきか、という部分が私は重要だと考えている。

Life is beautiful: スケーラビリティとユーザービリティの話

後者を私が採用するとすれば、例えばコメント投稿リクエストについては、リクエストをキューに入れ、クライアントには即「202 Accepted」を返します。

この方法の問題点としては、以下の2つが考えられます。

  • リクエストが成功するか、いつ反映されるのか、などとユーザが不安になるかもしれない
  • 処理成功/失敗時にビューを更新したければ、クライアントサイドスクリプトの助けが必要になる

特に「ユーザの不安」が私は気になります。ユーザビリティの向上を目指して非同期にした結果、ユーザの不安を招くとしたら、本末転倒なのではないでしょうか。

実は、単純な解決策があるのではないかと睨んでいます。過負荷の場合、リクエストを受け付けずに即「503 Service Unavailable」を返すのです。キューにたまっているリクエスト件数を見て、新規リクエストを含めN秒以内に実行完了できないようであれば、素直に白旗を上げてしまう。

ユーザは、サーバの混雑にイライラするかもしれませんが、結果が分からず不安になるよりはましではないか、というのが私の考えです。