ノンブロッキングIOはどの部分がノンブロッキングなのかを理解する

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リクエストとレスポンスの処理が並列化できても、内部がブロックしてしまうことになるからです。

関連情報