ご質問いただきありがとうございます、回答させていただきます。
シングルスレッドでBlocking I/Oであるランタイムを持つ言語はサーバー実装には向かないということでしょうか
向かないと言い切る事は難しいのですが、他のランタイムであるマルチスレッドでBlocking I/O かシングルスレッドで Non-Blocking I/O をサポートしている所の方が効率よく設計できると想います。後述します。
この話の前にプロセス、スレッドといった概念を正しく理解する必要があります。プロセスはCPUを利用するためのプログラムの一つです。スレッドはプロセス内部で複数起動可能で、それぞれCPUが複数コアあればタスクを並列に処理する事ができます。 Node.js はシングルスレッド、つまりプロセス内に一つしかスレッドを使いません(※細かく言うとファイルIOの時などは複数スレッドも使っていたり、ワーカースレッドもあり、最近だとマルチスレッドもあるのですが、一旦省きます)。
プロセスは複数起動可能です。なので、「シングルスレッドでBlocking I/Oであるランタイムを持つ言語」はプロセスを複数起動しておくことで処理を分散することが可能です。RubyやPerl、PHP、PythonなんかはそのようにしてI/Oの待ち時間に対応しています。ただし、複数起動しておくといっても限界があります。プロセスにはプロセス番号と呼ばれる番号があり、その数には制限があります。また1つあたりのプロセスに割り当てるメモリの量にも限界があります。物理的なメモリサイズを超えられないので、これも制限になります。この制限にあたったら複数のマシンで対応します。
シングルスレッドで Non-blocking I/O の Node.js は一つのプロセスがIO待ちの時にプロセスを起動することなく別リクエストを処理することが可能です。この観点で言えば、 Node.js の方がプロセスを複数起動しなきゃいけない言語よりもアドバンテージがあります。
そもそも一般的な Web アプリケーションは複数の処理があります。典型的な処理で言えば、
HTTPリクエストを受けつけ、
データベース・他サービス等へリクエスト発行し、
その処理が終わったらHTMLを作り、
HTTPレスポンスに入れて送り返します。
さて、ウェブアプリケーションの性質にもよりますが、ほとんどのウェブアプリケーションにおいては、その大部分の時間を2 のデータベースや他サービスへのリクエストに費やしています。SQLやネットワークリクエストを発行してから処理が終わりデータがもらえるまでの時間、言ってしまえば「データベース・他サービスの処理の待ち時間」に該当する部分が一番時間がかかります。
その時間を早くする事もチューニングには大事ですが、「じゃあその時間に別な作業をさせられるようにしてしまえば良くない?」という発想が生まれます。
PHP, Perl, Ruby, Python といった言語はこの時にマルチプロセスで対処します。Node.jsはこの時に non-blocking IO で対処し、プロセスは原則一つです。non-blocking IOにより、IO待ち時間が発生しているタイミングであっても複数のHTTPリクエストを処理することが可能です。
じゃあこの方法が最良なのかというと、それは違います。
non-blocking IO はマルチプロセス・マルチスレッドと比較すると CPU を使う処理に弱いです。一つしかプロセスが無いという事はCPUを専有してしまう処理があると、他のリクエストの処理ができなくなります。上記の処理で言うと、 3 のHTMLを作るという処理はHTMLという文字列を構築するために、 CPU を専有してしまう処理になります。
Node.js にもマルチスレッドの cluster やマルチスレッドの worker といった方法でCPUの専有問題を軽減することも可能ですが、根本的にCPUを使ってしまうということには変わりはなく、結局複数台で処理をしなくてはならなくなるケースが多いです。
なので、
シングルスレッドでBlocking I/Oであるランタイムを持つ言語はサーバー実装には向かないということでしょうか
という質問に対しての回答としては「IO待ちが問題になるウェブアプリケーションにおいては不利です。一方で、CPU専有が問題になるウェブアプリケーションにおいては大差がないです。」になります。どちらの場合であっても処理を分散させる必要はあり、結局大規模なトラフィックを捌くケースだと複数台であったり、複数プロセスだったり、複数スレッドを検討しないといけなくなります。ただ雑に一台だけで処理を受け付けてもそこそこ捌くのは Node.js みたいなシングルスレッド、ノンブロッキングIOのモデルの方が有利と言えると思います。