ノンブロッキングIOはどの部分がノンブロッキングなのかを理解する / Mojolicious
Mojoliciousが持っているWebサーバーはノンブロッキングIOに対応しています。でもノンブロッキングといったときには、人それぞれにいろんなイメージを抱いていると思いますし、誤解がたくさんある気がするので簡単に解説します。
ノンブロッキングなのは、HTTPリクエストを読み取る部分と書き込む部分
Mojoliciousがノンブロッキングなのは、HTTPリクエストを読み取る部分と書き込む部分です。ですので、たとえば複数の10Mバイトのファイルをレスポンスとして返す場合は、並列で処理することができます。またアップロードで複数の10Mバイトのファイルをリクエストとして受け取るときは、並列に処理することができます。
データベースアクセスはノンブロッキングではない
一般的にデータベースアクセスはノンブロッキングではありません。MySQLやSQLiteへのアクセスはブロッキングな処理になります。
ですから、Mojoliciousを使っているからといって、単純に全部がノンブロッキングになってくれるわけではなくって、データベースへアクセスする部分はブロッキングします。
たとえば処理に30秒かかる処理が、あるとすれば、その部分で30秒ブロッキングします。後続の処理はこれを待っている間は処理を行うことができません。
もしそういう処理がある場合は、ノンブロッキングIOのWebサーバーとしてではなくって、純粋なプリフォークサーバーとして運用するのがおそらくよいでしょう(まだ試していません)。並列処理のクライアント(clients)の数を減らして、プリフォークする数(workers)を増やします。
hypnotoad => { clients => 1, workers => 10 }
Mojoliciousを使うときは、処理の中に長くブロックする処理があると、デフォルトの設定では、後続の処理がとまってしまうということを覚えておきましょう。
データベースアクセスをノンブロッキングにするにはどうすればよいか
これは難しい問題で、一般的な方法では簡単に解決することができません。アーキテクチャー的には、フレームワークが内部で利用しているひとつのIOループの中に、処理を組み込むしかないのですが、これは非常に困難ですし、各データベースモジュールが対応している必要があります。
一番簡単なのはMojoliciousの作者が提供しているMangoというMongoDBへアクセスするためのモジュールを使うことです(まだ実験的な段階)。Mojolicious + MongoDBという組み合わせであれば、すべての処理をノンブロッキングで行うことが比較的簡単です。
ファイルを読み込む処理はノンブロッキングではない
通常Perlでファイルを読み込む処理を書く場合は、ノンブロッキングな処理ではなくてブロックする処理になります。ですから、大量に処理が必要となるコンテンツ配信サーバーを書きたい場合は、普通のファイル入出力の処理を書いてはいません。
AEをインストールして、AnyEventを使って、ファイルを読み込む部分を、ノンブロッキングで書く必要があります。こうしないと、HTTPリクエストとレスポンスの処理が並列化できても、内部がブロックしてしまうことになるからです。