簡単なNodeJS実現のプロセス間通信の例を書きました.

8228 ワード

1.clusterの紹介
皆さんはnodejsが単一プロセスの単一スレッドのサーバーエンジンであることを知っています.どんなに強力なハードウェアがあっても、単一CPUで計算するしかないです.そこで、第三者のclusterを開発し、nodeがマルチコアCPUを利用して並行して実現できるようにしました.nodejsの発展に従って、nodejsに環境を生産させて、多プロセスの多核処理を支持しなければなりません.V 0.0.6バージョンでは、Nodejsにclusterの特性が内蔵されています.これにより、Nodejsはついに独立したアプリケーション開発ソリューションとして目に映るようになりました.
clusterはnodejs内蔵のモジュールで、nodejs多核処理に用いられます.clusterモジュールは、多プロセス並列化プログラムの開発難易度を簡略化し、負荷バランスのためのクラスタを容易に構築することができます.
2.clusterの動作原理
各ワーカープロセスはchild_を使うことによってprocess.fork関数は、IPC(Inter-Parocess Communication、プロセス間通信)に基づいて、masterプロセスとの間の通信を実現します.
workerがserver.listen(...)関数を使用するとパラメータシーケンスをmasterプロセスに伝えます.マスタープロセスがworkersにマッチしたら、最後の文を労働者に伝えます.マスターがワーカーにマッチしていない場合は、ワーカーを作成して、文を伝えてワーカーに伝えます.
境界条件では、3つの面白い行動があります.注:下のserver.listenは、下の「http.Server-」net.Server類への呼び出しです.
  • 1.server.listen({fd:7}:masterとworkerの通信過程で、ファイルを転送することによって、masterは「ファイル記述は7」であって、「ファイル記述は7」の参照を転送するのではなく、「ファイル記述は7」を傍受します.
  • .server.listen(handle):masterとworkerの通信プロセスは、handle関数を介して通信し、プロセス連絡なしに
  • に通信する.
  • .server.listen(0):masterとworkerの通信プロセスでは、クラスタ内のworkerはランダムポートを開いて共有し、socket通信によって、上記の例の57132
  • のように通信する.
    複数のプロセスが同じリソースにある場合、オペレーティングシステムの負荷バランスは非常に効率的である.Node.jsにはルーティングロジックがありません.worker間に共有状態がありません.したがって、プログラムはメモリベースのsessionなど、簡単に設計する必要があります.
    ワーカーは独力で運行していますので、プログラムの必要に応じて独立して削除または再起動できます.ワーカーは互いに影響しません.ウォーカーが生きている限り、マスタは接続を受信し続けます.Nodeは自動的にworkersの数を維持しません.私たちは自分の接続池を作ることができます.
    3.clusterのAPI
    公式サイトのアドレス:http://nodejs.org/api/cluster.html#cluster_cluster
    clusterオブジェクトの各種属性と関数
  • cluster.settings:クラスタパラメータオブジェクト
  • を構成する.
  • cluster.isMaster:マスターノード
  • ではないかと判断する.
  • cluster.isWorker:ワーカーノード
  • であるかどうかを判定する.
  • Event:'fork':workプロセス作成イベントを傍受する
  • Event:'online':ウォーカーを待ち受けて成功イベントを作成しました.
  • Event:'listening':モニターワーカーがmaster状態イベント
  • に向かう.
  • Event:'disconnect':ウォーカー切断イベントを傍受する
  • Event:'exit':worker退出イベントを傍受する
  • Event:'setup':setupMasterイベントを傍受する
  • cluster.setupMaster(settings):クラスタパラメータを設定する
  • cluster.fork(env):workプロセス
  • を作成する.
  • cluster.disconnect(calback):worketプロセスを閉じる
  • cluster.worker:現在のworkerオブジェクト
  • を取得する.
  • cluster.workers:クラスタ内で生存している全てのウォーカーオブジェクト
  • を取得する.
    workerオブジェクトの各種属性と関数:cluster.workersを通じて、cluster.worketが得られます.
  • worker.id:プロセスID番号
  • worker.process:ChildProcessオブジェクト
  • worker.suicide:disconnect()後、workerが自殺したかどうかを判断する
  • worker.send:masterはworkerにメッセージを送ります.注:workerがmasterにメッセージを送るにはprocess.send
  • を使います.
  • worker.kill([signal='SIGTRM]):指定されたウォーカーを殺し、別名destory()
  • worker.disconnect():workカーを切断し、workerを自殺させます.
  • Event:'message':マスターとウォーカーのメッセージイベントを傍受する
  • Event:'online':指定されたウォーカーを傍受して成功イベントを作成する
  • Event:'listening':マスター・ウォーカー状態イベントを傍受する
  • Event:'disconnect':ウォーカー切断イベントを傍受する
  • Event:'exit':worker退出イベントを傍受する
  • 4.マスターとワーカーの通信例
    var cluster = require('cluster');
    var http = require('http');
    var numCPUs = require('os').cpus().length;
    
    if (cluster.isMaster) {
        console.log('[master] ' + "master started, pid:" + process.pid);
    
        cluster.on('fork', function (worker) {
            console.log('[master] ' + 'fork: worker' + worker.id);
        });
    
        cluster.on('online', function (worker) {
            console.log('[master] ' + 'online: worker' + worker.id);
        });
    
        cluster.on('listening', function (worker, address) {
            console.log('[master] ' + 'listening: worker' + worker.id + ',pid:' + worker.process.pid + ', address:' + address.address + ":" + address.port);
        });
    
        cluster.on('disconnect', function (worker) {
            console.log('[master] ' + 'disconnect: worker' + worker.id);
        });
    
        cluster.on('exit', function (worker, code, signal) {
            console.log('[master] ' + 'exit worker' + worker.id + ' died, try to fork a new worker.');
            cluster.fork();
        });
    
        for (var i = 0; i < numCPUs; i++) {
            cluster.fork();
        }
    
        Object.keys(cluster.workers).forEach(function (id) {
            cluster.workers[id].on('message', function (msg) {
                console.log('[master] ' + 'received msg:' + msg + 'from worker' + id);
            });
        });
    
        function eachWorker(callback) {
            for (var id in cluster.workers) {
                callback(cluster.workers[id]);
            }
        }
    
        var i = 0;
        setTimeout(function () {
            eachWorker(function (worker) {
                i++;
                worker.send('[master] ' + 'send msg ' + i + ' to worker' + worker.id);
            });
        }, 3000);
    
    } else if (cluster.isWorker) {
        console.log('[worker] ' + "worker" + cluster.worker.id + " started, pid:" + process.pid);
    
        process.on('message', function (msg) {
            console.log('[worker] worker' + cluster.worker.id + ' received msg:' + msg);
            process.send('[worker] send msg ' + cluster.worker.id + ' to master.');
        });
    
        http.createServer(function (req, res) {
            var response = 'worker received request, id:' + cluster.worker.id + ',pid:' + process.pid;
            console.log(response);
            res.writeHead(200, { "content-type": "text/html" });
            res.end(response);
        }).listen(5000);
    
    }