⌚ 2020/12/ 7 (Mon) 🔄 2024/3/20 (Wed)
Node.jsに対するSpringの答え - Spring WebFlux
Node.jsがSpringよりも性能が上の場合もあるという話があります。
JavaScriptがJavaより性能が良いわけがない、と信じていた人には信じがたい話かな
と思いますが、
これはいくつかのベンチマークにより明らかになっている事実です。
なら、Node.jsがSpringよりも良い性能を見せる根本的な理由はなんでしょうか。
そして、その理由に対するSpringの対策は何があるのでしょうか。
マルチスレッドvsシングルスレッド
Javaはマルチスレッドに対応する言語であり、一つの処理は一つのスレッドで行います。
なので同時に複数の要請を処理する場合は、複数のスレッドで処理することとなりますね。
Javaがそうなので、Springもまたそのようなスレッドプール基盤のデザインとなっています。
しかし、Node.jsを動かすJavaScriptでは、マルチスレッドの運用ができなません。
なので単一の要請であろうが、複数の要請であろうが、処理はシングルスレッドで行われます。
Node.jsがシングルスレッドなのに、マルチスレッドのSpringと同等、もしくはより良い
パフォーマンスを見せるケースがあるのはなぜでしょうか。
大抵の場合、作業は並列で行うのが効率的になるのが当然ですので。
しかし、実際はスレッドの数よりも、「同期か非同期か」「ブロッキングかノンブロッキングか」を考える必要があります。
Springは同期・ブロッキングでリクエストを処理し、Node.jsは非同期・ノンブロッキングで
リクエストを処理しますが、この違いが性能の差を生み出しています。
非同期・ノンブロッキングであること
それでは、同期・ブロッキングと非同期・ノンブロッキングはどう違うのでしょう。
例えばお寿司屋で例えて見ましょう。同期・ブロッキング方式は、伝統的なお寿司屋といえます。
寿司職人(スレッド)が顧客(クライアント)から注文(リクエスト)を受け、お寿司(レスポンス)を
作り、顧客から注文されたお寿司を提供すまで寿司職人が責任を持って業務を行います。
これが非同期・ノンブロッキングだと、処理の方式が大きく変わります。
例えば回転寿司のようになります。顧客から注文があったら、板前さんはまず注文を
受け付いたことだけを伝え、他の注文も受け取り最も時間のかからないお寿司から作って
コンベアに載せます。そしてコンベアがぐるぐる回りながら顧客にお寿司を伝達します。
この処理方式によって、複数のリクエストに対する処理のスピードが変わります。
同期・ブロッキング方式だと、スレッドが一つのリクエストに対して、レスポンスを返すまで
ロックされるので、このような構造のアプリにおいて、同時実行性能(複数の要請があった場合の性能)の
基準はあくまで「スレッドの数」となります。
同時に処理できるのはあくまでスレッドの数に限られるということです。
しかし、非同期・ノンブロッキング方式だと一つのスレッドだとしても複数のリクエストを
同時に受け取り、処理の終わった順でレスポンスを返すという効率的な処理をするので、
比較的少ないスレッド数でも同等か優位の性能を見せることができるのです。
このような非同期・ノンブロッキングの特徴のおかげで、シングルスレッドで処理を行い
ながらも、Node.jsはSpringよりも良い性能を実現することができるということになリます。
だからNode.js > Spring?
確かな事実は、非同期・ノンブロッキングは以下の状況で、同期・ブロッキング方式より
良い性能を期待できるということです。
1. 同時実行性能が重要
2. I/Oが多い
3. 複雑な演算(CPUの消耗が激しくない)が多い
これらは、現在のWebアプリケーションならどれでも共有している特徴と言えます。
つまり、Node.jsがSpringと比べて性能が高いと言われる理由は、Node.jsの持つ
非同期・ノンブロッキングとしての特徴がWebアプリケーションと一致しているから、
という結論になります。
それでは、そもそも同期・ブロッキング方式のSpringではNode.jsのような性能は
期待できないのかという疑問が湧いてくると思います。
しかし、Javaでもすでに1.7から導入したNIOで、ノンブロッキングでI/Oができるように
なっています。
ならば、Java(Spring)でも非同期・ノンブロッキングでリクエストを処理するのは
不可能ではなさそうにも見えます。では、実際はどうでしょうか。
Springではどのようにこの問題に対応しているのでしょうか。
WebFluxという答え
Spring 5では、既存のSpring MVCとは区別されるフレームワークとして
Spring WebFluxが新しく発表されました。
そして、このWebFluxが、Springにおいて非同期・ノンブロッキングのI/Oのできるものです。
もちろんJavaがマルチスレッド対応の言語なので、Spring WebFluxはNode.jsと違って
マルチスレッドながらも非同期・ノンブロッキングで処理を行うというところが特徴です。
他にもMVCと比べ、CPUやメモリーの使用量が少ないというメリットがあり、
イベント・ドリブンなど最近のトレンドを反映したアーキテクチャが特徴と言えます。
ただし、Spring WebFluxが導入されたことで、全ての問題が解決されたかというと、
実際はそうでもありません。
WebFluxは処理のうちに一つでも同期・ブロッキングが発生すると、MVCよりも性能が劣ると
言われています。
また、単一のリクエストに対してもMVCより性能が優れているわけでもありません。
性能以外の観点からすると、Spring SecurityやSpring Dataなど、他の依存関係においてもWebFluxのために
新しく作成されたライブラリを使う必要があるためWebFluxを導入するのは慎重に判断する必要があります。
なので、MVCで作成されたアプリに特に問題がなかったら、わざわざWebFluxを導入する
必要はなく、マイクロサービスやBFFとして完全新規のサービスを作る必要があるときに
候補として検討できる、というのが大抵の結論となっているらしいです。
それでも未来はWebFlux
今は上述の通り、さまざまな懸念があるためすぐに既存のアプリをWebFluxに移行するのは
難しいですが、それでもWebFluxの将来的に導入を考慮すべき理由は明確です。
これからのアプリは、ますます同時実行性能が大事になり、さらにマイクロサービス化する
ということです。
また、SpringとしてもRestTemplateをWebClientに変えるなどWebFluxに力を入れている
からです。
つまり、いずれはMVCがWebFluxを代替することとなるかも知れない状況です。
なので、今からでも、Spring WebFluxに足を踏み入れてみた方が良いのではないかと思います。
みなさんもぜひ、今からWebFluxで変わるSpringの未来を体験してみませんか。
==もちゴリ==