Node.jsと非同期I/Oと混乱した私
最近、Node.jsに興味があります。Node.jsを調べていると、I/O関係で、非同期I/O、ノンブロッキング、コールバック等、いろいろとキーワードがでてきて混乱してきます。
そこで、ブログに書いて整理しよう思います。間違いがあれば是非、指摘してください。
言葉の定義
◇非同期呼び出し(Asynchronous Call)と同期呼び出し(Synchronous Call)の違い
- 同期呼び出し(Synchronous Call)
- 通常メソッドを呼び出すとメソッド内の処理が完了するまで、呼び出し元には戻ってこない。このようなメソッド呼び出しのこと。
- 非同期呼び出し(Asynchronous Call)
- メソッドを呼び出した瞬間に呼び出し元に処理が戻ってくるような呼び出しのこと。非同期で呼び出されたメソッドは、環境によって処理されるタイミングが変わる。
◇マルチスレッド(multithread)とコールバック(callback)の非同期処理の違い
- マルチスレッド(multithread)による非同期処理
- 呼び元と並行に処理が行われる。
- コールバック(callback)による非同期処理
- 呼び元がプロセッサを使用していないときに処理が行われる。
I/Oモデル
W. Richard Stevensの「UNIXネットワークプログラミング 第2版 Vol.1」では、I/Oモデルは以下のように分類できるそうです。
- Synchronous I/O Operation (同期I/O操作)
- Asynchronous I/O Operation (非同期I/O操作)
- Asynchronous I/O (非同期I/O)
また、developerWorksの「Boost application performance using asynchronous I/O」によると
以下の図のように分類できるようです。
この図では、I/O multiplexingがAsynchronousに分類されていますね。
なぜでしょうか。。このAsynchronousは、I/O Operationのことではなく、通知のことであるI/Oが可能になった通知を非同期に受ける(非同期通知)という見方もあるようですが、私は違うような気がします。
例えば、select()を使った場合、I/O可能になるまで待たされるか、タイムアウトをつけて定期的にチェックすることになります。その場合、同期的に通知を受けることになると思います。
developerWorksの記事では、I/O multiplexingについて、あまり触れられておりませんので、
なぜこうなっているのかよくわかりません。。
自分が非同期通知について、勘違いしているのでしょうか。。
また、「C10K問題」というのがあります。C10Kとは、クライアント1万台のことであり、ハードウェアの性能上は問題がなくても、あまりにもクライアントの数が多くなるとサーバがパンクする問題のことです。
詳しくは、リンク先を読んで欲しいのですが、解決方法として、以下の方法が挙げられています。
- 各スレッドが複数のクライアントを受け付ける。 そしてノンブロッキング I/O と レベル・トリガ型の完了通知(level-triggered readiness notification)を利用する。
- 各スレッドが複数のクライアントを受け付ける。 そしてノンブロッキング I/O と 変更型の完了通知(readiness change notification)を利用する。
- 各スレッドが複数のクライアントを受けつける。 そして非同期 I/O を使う。
- 各スレッドが一つのクライアントを受けつける。 そしてブロッキング I/O を使う
- サーバのコードをカーネルに組込む。
Node.jsでは、「3. 各スレッドが複数のクライアントを受けつける。 そして非同期 I/O を使う」を採用しているようです。
Node.jsでは、「libev」と「libeio」を使用して、非同期I/O環境を実装しています。
「libev」は、C言語で書かれたイベントループライブラリです。
イベントループとは、無限ループを行いながら、I/Oを監視し、利用可能やI/O完了等のイベントが発生するとコールバックにより通知します。
I/Oの監視には、I/O multiplexingモデルを使用し、環境によって最適なシステムコール(Linuxであれば、epoll、FreeBSDでは、kqueue)を使用します。
先程の「Boost application performance using asynchronous I/O」の図の左下(Asynchronous + Blocking)に「libev」は位置するのではないかと思います。