ホームページ > ウェブフロントエンド > jsチュートリアル > Node.js の高同時実行性と分散クラスタリングに関する簡単な説明

Node.js の高同時実行性と分散クラスタリングに関する簡単な説明

不言
リリース: 2018-08-01 15:54:46
オリジナル
2908 人が閲覧しました

この記事では、node.js における高同時実行性と分散クラスターについて簡単に説明します。必要な方は参考にしていただければ幸いです。

ノードの機能: 高い同時実行性

なぜノードが高い同時実行性を達成できるのかを説明する前に、ノードの他のいくつかの機能を理解しておくとよいでしょう:

シングルスレッド

まず概念を明確にしましょう。つまり、ノードは シングルスレッド、これはブラウザのJavaScriptの特性と同じであり、ノードでは、JavaScriptのメインスレッドは他のスレッド(I/Oスレッドなど)と状態を共有できません。 单线程的,这一点与JavaScript在浏览器中的特性相同,并且在node中JavaScript主线程与其他线程(例如I/O线程)是无法共享状态的。

单线程的好处就是:

  • 无需像多线程那样去关注线程之间的状态同步问题

  • 没有线程切换所带来的开销

  • 没有死锁存在

当然单线程也有许多坏处:

  • 无法充分利用多核CPU

  • 大量计算占用CPU会导致应用阻塞(即不适用CPU密集型)

  • 错误会引起整个应用的退出

不过在今天看来,这些坏处都已经不再是问题或者得到了适当的解决:

(1) 创建进程 or 细分实例

关于第一个问题,最直白解决方案就是使用child_process核心模块或者cluster:child_process 和 net 组合应用。我们可以通过在一台多核服务器上创建多个进程(通常使用fork操作)来充分利用每个核心,不过要处理好进程间通信问题。

另一个方案是,我们可以将物理机器划分为多台单核的虚拟机,并通过pm2等工具,管理多台虚拟机形成一个集群架构,高效运行所需服务,至于每台机器间的通信(状态同步)我这里先按下不表,在下文的Node分布式架构中再做详细说明。

(2) 时间片轮转

关于第二点,我跟小伙伴讨论过后认为可以通过时间片轮转方式,在单线程上模拟多线程,适当减少应用阻塞的感觉(虽然这种方法不会真的像多线程那样节约时间)

(3) 负载均衡、坏点监控/隔离

至于第三点,我跟小伙伴们也讨论过,认为主要的痛点就在于node不同于JAVA,它所实现的逻辑是以异步为主的。

这就导致了node无法像JAVA一样方便地使用 try/catch 来来捕获并绕过错误,因为无法确定异步任务会何时传回异常。而在单线程环境下,绕不过错误就意味着导致应用退出,重启恢复的间隙会导致服务中断,这是我们不愿意看到的。

当然,在服务器资源丰富的当下,我们可以通过 pm2 或 nginx 这些工具,动态的判断服务状态。在服务出错时隔离坏点服务器,将请求转发到正常服务器上,并重启坏点服务器以继续提供服务。这也是Node分布式架构的一部分。

异步I/O

你可能会问,既然node是单线程的,事件全部在一个线程上处理,那不是应该效率很低、与高并发相悖吗?

恰恰相反,node的性能很高。原因之一就是node具有异步I/O特性,每当有I/O请求发生时,node会提供给该请求一个I/O线程。然后node就不管这个I/O的操作过程了,而是继续执行主线程上的事件,只需要在该请求返回回调时在处理即可。也就是node省去了许多等待请求的时间。

这也是node支持高并发的重要原因之一

实际上不光是I/O操作,node的绝大多数操作都是以这种异步的方式进行的。它就像是一个组织者,无需事必躬亲,只需要告诉成员们如何正确的进行操作并接受反馈、处理关键步骤,就能使得整个团队高效运行。

事务驱动

你可能又要问了,node怎么知道请求返回了回调,又应该何时去处理这些回调呢?

答案就是node的另一特性:事务驱动

シングルスレッドの利点は次のとおりです:

マルチスレッドのようなスレッド間の状態同期の問題に注意を払う必要がありません

スレッドの切り替えによるオーバーヘッドがありません

デッドロック

  • もちろん、シングルスレッドには多くの欠点もあります:

マルチコア CPU を完全に活用できない

  • CPU を占有する大量の計算により、アプリケーションのブロックが発生します (つまり、CPU に適さない) -集中的)

  • エラーによりアプリケーション全体が終了します

    🎜 🎜しかし、現在では、これらの欠点は問題ではなくなっているか、適切に解決されているようです: 🎜🎜(1) プロセスを作成するか、インスタンスを細分化する🎜🎜 最初の問題に関して、最も簡単な解決策は、child_process コア モジュールまたはクラスター: child_process と net を組み合わせたアプリケーションを使用することです。マルチコア サーバー上に複数のプロセスを作成する (通常はフォーク操作を使用する) ことで各コアを最大限に活用できますが、プロセス間の通信の問題に対処する必要があります。 🎜🎜もう 1 つの解決策は、物理マシンを複数のシングルコア仮想マシンに分割し、pm2 などのツールを使用して複数の仮想マシンを管理し、必要なサービスを効率的に実行するためのクラスター アーキテクチャを形成することです。通信(状態同期) ここでは今回は記載せず、以下のノード分散アーキテクチャで詳しく説明します。 🎜🎜(2) タイムスライスローテーション🎜🎜 2点目については、友達と話し合った結果、タイムスライスローテーションを使ってシングルスレッド上でマルチスレッドをシミュレートし、アプリケーションのブロッキング感を適切に軽減できるのではないかと思います(ただしこれは問題ありません)。マルチスレッドのように本当に時間を節約できます)🎜🎜(3) 負荷分散、不良ピクセルの監視/分離🎜🎜 3番目の点については、私も友人と議論しましたが、主な問題点はノードは JAVA とは異なり、実装されるロジックは主に非同期です。 🎜🎜これにより、非同期タスクがいつ例外を返すかを判断することが不可能なため、ノードは try/catch を使用して JAVA と同様にエラーをキャッチしてバイパスすることができなくなります。シングルスレッド環境では、エラーのバイパスに失敗するとアプリケーションが終了することを意味し、再起動と回復の間のギャップによりサービスが中断されることになりますが、これは望ましくないことです。 🎜🎜もちろん、今ではサーバーリソースが豊富なので、pm2やnginxなどのツールを使用してサービスの状態を動的に判断できます。サービス エラーが発生した場合は不良ピクセル サーバーを隔離し、リクエストを通常のサーバーに転送し、不良ピクセル サーバーを再起動してサービスの提供を継続します。これも Node の分散アーキテクチャの一部です。 🎜🎜非同期 I/O🎜🎜 ノードはシングルスレッドであり、すべてのイベントが 1 つのスレッドで処理されるため、非同期 I/O は非常に非効率であり、高い同時実行性に反するのではないかと疑問に思われるかもしれません。 🎜🎜それどころか、ノードのパフォーマンスは非常に高いです。理由の 1 つは、ノードに 非同期 I/O 機能があるため、I/O リクエストが発生すると、そのリクエストに対して I/O スレッドが提供されます。その後、ノードは I/O 操作プロセスを気にせず、メインスレッドでイベントを実行し続けますが、リクエストがコールバックを返したときにのみ処理する必要があります。つまり、ノードはリクエストを待つ時間を大幅に節約します。 🎜🎜🎜これは、ノードが高い同時実行性をサポートする重要な理由の 1 つでもあります🎜🎜🎜実際、I/O 操作だけでなく、ノードのほとんどの操作はこの非同期方法で実行されます。オーガナイザーは、個人的にすべてを行う必要はなく、チーム全体が効率的に運営できるように、メンバーに正しい操作方法、フィードバックの受け入れ方法、主要な手順の処理方法を伝えるだけで済みます。 🎜🎜トランザクション駆動🎜🎜もう一度尋ねたいかもしれませんが、ノードはリクエストがコールバックを返したことをどのようにして知るのでしょうか?また、これらのコールバックをいつ処理する必要があるのでしょうか? 🎜🎜その答えは、ノードのもう 1 つの機能である トランザクション ドライバー です。つまり、メイン スレッドがイベント ループ トリガーを通じてプログラムを実行します 🎜🎜🎜これが、ノードが高い同時実行性をサポートするもう 1 つの重要な理由です 🎜🎜 🎜ノード環境のイベント ループの図: 🎜
       ┌───────────────────────┐
    ┌─>│        timers         │🎜🎜ポーリング フェーズ: 🎜🎜🎜ポーリング フェーズに入り、タイマーが呼び出されないと、次の状況が発生します: 🎜🎜 (1) ポーリング キューが空でない場合 : 🎜🎜🎜🎜イベント ループは、キューが空になるか、実行されたコールバックがオンラインになるまで、ポーリング キュー内のコールバック (新しい I/O イベント) を同期的に実行します。 🎜🎜🎜🎜(2) ポーリング キューが空の場合: 🎜🎜🎜🎜 スクリプトが setImmediate() を呼び出すと、イベント ループはポーリング フェーズを終了し、setImmediate() コールバックを実行するチェック フェーズに入ります。 🎜🎜🎜🎜スクリプトが setImmediate() によって呼び出されない場合、イベント ループはコールバック (新しい I/O イベント) がキューに追加されるのを待機し、すぐに実行します。 🎜
    ログイン後にコピー

ポーリングフェーズに入り、タイマーが呼び出されると、次のことが起こります:

  • ポーリングキューが空になると、イベントループはタイマーがあるかどうかを確認し、1つ以上のタイマーが到着した場合、イベントループは戻りますタイマー フェーズに移行し、それらのタイマー コールバックを実行します (つまり、次のティックを入力します)。

Priority:

Next Tick Queue > MicroTask Queue

setTimeout, setInterval > setImmediate

タイマーは時間が到来したかどうかを判断するために赤黒ツリーからタイマーを取り出す必要があるため、時間計算量は O (lg(n)) なので、イベントを非同期ですぐに実行したい場合は、setTimeout(func, 0) を使用しないことをお勧めします。代わりに process.nextTick() を使用してこれを実行します。

分散ノードアーキテクチャ

私が学んだノードクラスターアーキテクチャは主に次のモジュールに分かれています:

Nginx (ロードバランシング、スケジューリング) -> ノードクラスター -> Redis (同期ステータス)

コンパイルしました私の理解に基づく図:

Node.js の高同時実行性と分散クラスタリングに関する簡単な説明

もちろん、これは理想的なアーキテクチャであるはずです。 Redis の読み取り/書き込みは非常に高速ですが、これはメモリ プールにデータを保存し、メモリ上で関連する操作を実行するためです。

これはサーバーのメモリ負荷としては非常に高いので、通常は以下に示すように Mysql をアーキテクチャに追加します:

Node.js の高同時実行性と分散クラスタリングに関する簡単な説明

まずこの図について説明します:
ユーザーデータが到着すると、データは次のように書き込みます。まず Mysql にアクセスし、ノードでデータが必要なときに Redis にアクセスして読み取ります。データが見つからない場合は、Mysql にアクセスして目的のデータをクエリし、次回使用するときに Redis に直接アクセスしてください。クエリ。

Redis での読み取り/書き込みのみと比較した Mysql の追加の利点は次のとおりです:

(1) 短期的に Redis に無駄なデータを書き込むことを避け、メモリを占有し、Redis の負担を軽減します

(2) 修正が必要後の段階のデータ 特定のクエリと分析 (運用アクティビティのユーザーの増加の分析など) を実行する場合、SQL リレーショナル クエリは大きな助けになります

もちろん、短期的な大量の書き込みを処理する場合は、データを Redis に直接書き込むこともできます。データを迅速に保存し、トラフィックに対処するサーバーの能力を高めるという目的を達成するために、データはトラフィックが落ち着いたときに個別に MySQL に書き込まれます。

一般的なアーキテクチャを簡単に紹介した後、各部分の詳細を詳しく見てみましょう:

トラフィック アクセス層

トラフィック アクセス層の機能は、受け入れられたすべてのトラフィックを処理し、次のサービスを提供することです:

  • トラフィックバッファリング

  • 迂回と転送

Node.js の高同時実行性と分散クラスタリングに関する簡単な説明

  • タイムアウト検出

    • ユーザーとの接続を確立するためのタイムアウト

    • ユーザー本体がタイムアウトしました
    • 接続バックエンドタイムアウト
    • バックエンド応答ヘッダーの読み取りタイムアウト
    • 書き込み応答タイムアウト
    • ユーザーとの長い接続タイムアウト
    クラスターのヘルスチェック/不良サーバーの隔離
    • 不良サーバーをクリックそして試してみてくださいサーバーが正常に戻るまで修復/再起動します
    失敗再試行メカニズム
    • リクエストが特定のクラスタ内の特定のマシンに転送され、失敗が返された後、リクエストはクラスタ内の別のマシンに転送されます。クラスター、またはクラスター間のマシンで再試行します
    接続プール/セッション永続化メカニズム
    • 遅延に敏感なユーザーは、接続を確立する時間を短縮するために接続プールメカニズムを使用してください
    セキュリティ保護
  • データ分析
  • 各製品ラインに転送した後、負荷層が機能します。状況に応じてリクエストをさまざまなコンピュータールームに転送します

Node.js の高同時実行性と分散クラスタリングに関する簡単な説明もちろん、このプラットフォームはこの機能を転送するだけでなく、次のサービスを提供する大規模なプライベート クラウド システムとして理解できます:

    ファイルのアップロード/サービスのオンライン展開
  • オンライン構成の変更
  • スケジュールされたタスクの設定
  • オンラインシステム監視/ログ印刷サービス
  • オンラインインスタンス管理
  • ミラーセンター
  • など...
  • ノードクラスターレイヤー

この層の主な仕事は次のとおりです。

(1 )信頼性の高いノードコードを作成し、ニーズに合わせたバックエンドサービスを提供します

(2) 高パフォーマンスのクエリ ステートメントを作成し、Redis および Mysql と対話し、クエリ効率を向上させます

(3) Redis を介してクラスター内の各ノード サービスのステータスを同期します

(4) を介して物理マシンを管理/監視しますハードウェア管理プラットフォームのステータス、管理 IP アドレスなど (実際、作業のこの部分をこの層に配置するのは不適切な気がしますが、どの層に配置すればよいのかわかりません...)

(もちろん、この部分のエントリは簡単に列挙するだけですが、蓄積して深く理解するには時間がかかります)

データベース層

この層の主な作業は次のとおりです:

(1) MySQL の作成と関連するページとテーブルの設計; クエリの利便性を向上させるために必要なインデックスと外部キーを確立します

(2) Redis をデプロイし、対応するインターフェイスをノード層に提供します

関連する推奨事項:

vue がバックエンドデータをリクエストするためにどのように axios を使用するか

Vue のフォーム入力バインディングとコンポーネントの基本

以上がNode.js の高同時実行性と分散クラスタリングに関する簡単な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート