Node.jsで建てたサーバーでヘビーな処理をしてはいけない【それはそう】
小ネタです。
普段はフロントエンドを書いている人間なのですが、最近Goを学んだことをきっかけに非同期的な処理の仕組みについて、もう少し低いレイヤーで理解をしたいと思い、調べ物をしていました。
そこで目にしたこちらの記事に書いてあることが、当たり前と言われれば当たり前なことながら、知らずにやらかしそうだと感じたので、実際に実験してみたコードとともに紹介です。
const http = require('http');
const server = http.createServer((req, res) => {
// 何かしらのヘビーな処理(10秒経つまで無限ループ)
const now = new Date();
while(now.getTime() + 10 * 1000 > new Date().getTime()) {}
res.end()
});
server.listen(8080, '0.0.0.0');
こちらのNode.jsのコードを実行し、localhost:8080に対してリクエストを投げると10秒経ってレスポンスが返ってきます。ここまでは想像通りかと思うのですが、次にlocalhost:8080に対して2連続でリクエストを投げます。
そうするとどうでしょうか? おそらく片方のリクエストは10秒でレスポンスが返ってくると思いますが、もう片方のレスポンスはレスポンスが戻るまで20秒くらいかかるのではないでしょうか?
これが、タイトルにもある「Node.jsで建てたサーバーでヘビーな処理をしてはいけない」という話です。
なんでこんなことになるのか
冒頭の記事をご覧になった上でこの記事をみている方はすでにお分かりのことと思いますが、このような現象が発生する理由はNode.jsがシングルプロセスかつシングルスレッドで動作するため、複数の処理を同時に行うことはできないからというところにあります。
複数の処理を同時に行うことができないということは、2連続でリクエストを送ると1つ目のリクエストが終わるまで2つ目のリクエストは処理されないため最初のリクエストを処理していた10秒 + 後続のリクエストを処理していた10秒の合計20秒がかかったということになります。
まとめ
というようなことを知って、理解してみれば「それはそう」としか思わないことなのですが、いままであまりちゃんと理解してなかったなと感じたので恥を忍んで記事にしてみました。
冒頭の記事にもあるように、こういったリクエストを起点に重い処理をするようなコードはNode.jsで書いてはいけないということをちゃんと覚えておこうと思いました。
Promiseを使っても、結局並列に実行されているような気分になるだけで並列実行されているわけじゃないんだということを知識としてだけではなく身を持って学ばせていただきました。
おしまい
Discussion