2015-11-21 16 views
13

Il mio caso d'uso è il seguente: Faccio molte chiamate API di resto dal mio server di nodo alle API pubbliche. A volte la risposta è grande ea volte è piccola. Il mio caso d'uso mi impone di stringificare la risposta JSON. Conosco un grande JSON in quanto la risposta bloccherà il mio ciclo degli eventi. Dopo alcune ricerche ho deciso di utilizzare child_process.fork per analizzare queste risposte, in modo che le altre chiamate API non debbano attendere. Ho provato a inviare un grande file JSON da 30 MB dal mio processo principale al child_process forked. Ci vuole così tanto tempo prima che il processo figlio scelga e analizzi il json. La risposta che mi aspetto dal processo figlio non è enorme. Voglio solo stringificare e ottenere la lunghezza e inviare di nuovo al processo principale.Node.js - L'invio di un oggetto grande a child_process è lento

Im collegare il codice master e figlio.

var moment = require('moment'); 
var fs = require('fs'); 
var process = require('child_process'); 
var request = require('request'); 

var start_time = moment.utc().valueOf(); 

request({url: 'http://localhost:9009/bigjson'}, function (err, resp, body) { 

    if (!err && resp.statusCode == 200) { 

    console.log('Body Length : ' + body.length); 

    var ls = process.fork("response_handler.js", 0); 

    ls.on('message', function (message) { 
     console.log(moment.utc().valueOf() - start_time); 
     console.log(message); 
    }); 
    ls.on('close', function (code) { 
     console.log('child process exited with code ' + code); 
    }); 
    ls.on('error', function (err) { 
     console.log('Error : ' + err); 
    }); 
    ls.on('exit', function (code, signal) { 
     console.log('Exit : code : ' + code + ' signal : ' + signal); 
    }); 
    } 
    ls.send({content: body}); 
}); 

response_handler.js

console.log("Process " + process.argv[2] + " at work "); 

process.on('message', function (json) { 
    console.log('Before Parsing'); 
    var x = JSON.stringify(json); 
    console.log('After Parsing'); 
    process.send({msg: 'Sending message from the child. total size is' + x.length}); 
}); 

C'è un modo migliore per ottenere ciò che im cercando di fare? Da un lato ho bisogno della potenza di node.js per fare migliaia di chiamate API al secondo, ma a volte ho un grosso JSON che rovina tutto.

+0

Il tuo approccio sembra andare bene. Quando si dice "my node server", capisco che si tratta di un processo che serve i client.Hai davvero bisogno di fare le chiamate API dal tuo server? Non puoi delegare l'attività a diversi processi e impostare un canale di comunicazione tra loro e il tuo server come un broker di messaggi, Redis o semplicemente pipe o qualche altra forma di IPC? – kliron

+0

Il mio male, per chiamare questo come un server, si può considerare questo come un agente. Questo non serve a nessuno. Questo agente funge da client API altamente scalabile. – Vinoth

+0

Forse puoi usare lo streaming parser json piuttosto che farlo in un unico blocco con JSON. – mcfedr

risposta

3

L'attività sembra essere sia vincolata a IO (recupero di JSON da 30 MB di dimensioni) in cui l'asincronismo di Node risplende, sia al limite della CPU (analisi di 30 milioni di JSON) dove l'asincronicità non aiuta.

Bifare troppi processi diventa presto una risorsa e degrada le prestazioni. Per le attività legate alla CPU è necessario un numero di processi pari al numero di core e non più.

Vorrei utilizzare un processo separato per eseguire il recupero e delegare l'analisi a N altri processi, dove N è (al massimo) il numero dei core della CPU meno 1 e utilizza una qualche forma di IPC per la comunicazione di processo.

Una scelta è quella di utilizzare il modulo di Cluster Node per orchestrare tutto quanto sopra: https://nodejs.org/docs/latest/api/cluster.html

Utilizzando questo modulo, si può avere un processo maestro creare i processi di lavoro in anticipo e non hanno bisogno di preoccuparsi quando a forcella, quanti processi creare, ecc. IPC funziona come al solito con process.send e process.on. Quindi un possibile flusso di lavoro è:

  1. Avvio applicazione: processo master crea un processo "fetcher" e N "parser".
  2. fetcher invia un elenco di lavoro di endpoint API da elaborare e avvia il recupero di JSON rimandandolo al processo principale.
  3. su ogni JSON scaricato che il master invia a un processo parser. Potresti usarli in modalità round robin o utilizzare un modo più sofisticato di segnalazione per il processo master quando una coda di lavoro parser è vuota o sta per esaurirsi.
  4. I processi parser inviano l'oggetto JSON risultante al master.

Si noti che IPC ha anche un overhead non banale, soprattutto quando si inviano/ricevono oggetti di grandi dimensioni. Potresti anche fare in modo che il fetcher esegua l'analisi di risposte molto piccole invece di passarle in giro per evitare questo. "Piccolo" qui è probabilmente < 32 KB.

Vedi anche: Is it expensive/efficient to send data between processes in Node?

+0

Questo è esattamente quello che stavo cercando di fare. Il thread principale recupererà tutti i contenuti da varie API e il calcolo sarà gestito da processi separati. Il problema qui sta passando le risposte a questi nuovi processi. Ho dato un esempio semplificato, in cui sembra che sto per creare tanti processi quante sono le risposte. Ma sicuramente sto pensando di limitarlo al numero di core. Tuttavia non sto ottenendo come può essere orchestrato dai cluster di nodi. Fammi sapere se mi manca qualcosa qui. Se hai qualche suggerimento, per favore indicami quello. Apprezzo la tua risposta. – Vinoth

+0

@Vinoth Ho aggiornato la risposta. Dai un'occhiata alla documentazione di Cluster che è abbastanza semplice. – kliron

+0

Lo provo. Sembra che il presupposto qui sia di convogliare un grosso errore a parser dal master non richiederebbe tutto il tempo necessario nel mio esempio. Dove sto usando child_process.fork(). Dal momento che il cluster di nodi utilizza internamente child_process.fork() mi chiedo come possa comportarsi diversamente. Gli darò un colpo per confermare. Apprezzo la risposta. – Vinoth