2013-02-14 8 views
15

Possiedo un'app Node che accede a una struttura di dati statica, grande (> 100 M), complessa, in memoria, accetta le query e fornisce quindi piccole fette di tali dati al client su HTTP.C'è un modo per condividere la memoria tra worker/thread/qualcosa in Node.JS?

Alla maggior parte delle domande è possibile rispondere in decimi di secondo. Evviva il nodo!

Tuttavia, per alcune query, la ricerca di questa struttura dati richiede alcuni secondi. Questo fa schifo perché tutti gli altri devono aspettare.

Per servire più clienti in modo efficiente, vorrei utilizzare una sorta di parallelismo.

Ma, dato che questa struttura dati è così grande, mi piacerebbe condividerla tra i lavoratori o i thread o cosa hai, quindi non masterizzo centinaia di megabyte. Questo sarebbe perfettamente sicuro, perché la struttura dei dati non verrà scritta. Un tipico 'fork()' in qualsiasi altra lingua lo farebbe.

Tuttavia, per quanto posso dire, tutti i metodi standard per eseguire il parallelismo nel nodo lo rendono esplicitamente impossibile. Per sicurezza, non vogliono che tu condivida nulla.

Ma c'è un modo?

Background:

Non è pratico di mettere questa struttura dati in un database, o utilizzare memcached, o qualcosa di simile.

Le librerie API di WebWorker e simili consentono solo di inoltrare i messaggi in serie brevi agli operatori.

Cluster di nodi utilizza una chiamata denominata "fork", ma non è realmente un fork del processo esistente, ne genera uno nuovo. Quindi ancora una volta, nessuna memoria condivisa.

Probabilmente la risposta più corretta sarebbe utilizzare un accesso simile a un file system alla memoria condivisa, ovvero tmpfs o mmap. Ci sono alcune librerie di nodi che rendono mount() e mmap() disponibili esattamente per qualcosa del genere. Sfortunatamente, si deve implementare un complesso accesso alla struttura dati oltre a ricerche e letture sincrone. La mia applicazione utilizza matrici di matrici di dicts e così via. Sarebbe bello non dover reimplementare tutto ciò.

+0

Non puoi anticipare la ricerca (utilizzando 'process.nextTick' forse) in modo da non bloccare il resto? – robertklep

+3

'Non è pratico mettere questa struttura dati in un database, o usare memcached, o qualcosa del genere. Il cosa ?? Da quando? – freakish

+0

strambo: Stiamo controllando se ogni elemento è un sottoinsieme di una query. Immagina di avere una stringa "fooquux" e vogliamo verificare se "ox" è in quella stringa. Non c'è modo che io sappia di farlo in modo efficiente con le normali operazioni di database. Ma è super facile se puoi accedervi come una normale struttura dati. Quindi un gran numero di questi sono ordinati e classificati e questi sono "puntatori" a più dati, ancora poco pratici a meno che non li abbiamo in una struttura di dati. – NeilK

risposta

0

edificio con waf è vecchio stile (nodo 0.6 e sotto), la nuova build è con gyp.

Si dovrebbe esaminare il cluster di nodi (http://nodejs.org/api/cluster.html). Non è chiaro che questo ti aiuterà senza avere più dettagli, ma questo esegue più processi di nodo sulla stessa macchina usando fork.

+1

Il cluster non si biforca realmente - sta solo generando un nuovo processo. Il motivo per cui mi piacerebbe biforcarsi è condividere la memoria che so essere immutabile e che non verrà modificata dai bambini. – NeilK

+2

Proprio dalla voce che hai collegato a: "Questi nodi figlio sono ancora nuove istanze di V8. Assumi almeno 30 ms di avvio e 10 MB di memoria per ogni nuovo nodo. Cioè, non puoi crearne molte migliaia." E nel mio caso devo caricare> 100 MB in ciascuno. – NeilK

+0

@NeilK> 100 MB non è un grosso problema (a meno che> 100 MB non comprenda 10 GB: D). Ciò che è più importante è mantenere i dati sincronizzati tra le istanze. Per questo suggerisco di usare un server dedicato per mantenere quei dati. Vedi la mia risposta. – freakish

0

In realtà il nodo supporta i processi di spawning. Non sono sicuro di come chiudere la forcella del nodo è quello di vero e proprio bivio, ma si può provare:

http://nodejs.org/api/child_process.html#child_process_child_process_fork_modulepath_args_options

A proposito: non è vero che il nodo non è adatto per questo. È adatto come qualsiasi altro linguaggio/server web. Puoi sempre attivare più istanze del tuo server su porte diverse e mettere un proxy in primo piano.

Se è necessaria più memoria, aggiungere più memoria. :) È così semplice. Inoltre dovresti pensare a mettere tutti i dati su un database dedicato in memoria come Redis o Memcached (o anche Couchbase se hai bisogno di query complesse). Non dovrai più preoccuparti di duplicare questi dati.

+2

Leggere la documentazione che mi hai appena collegato a. Fino alla fine. :) Inoltre, mentre potrebbe essere possibile avere diversi processi con copie di una struttura dati di 100 milioni con un budget modesto, lo sto facendo come progetto parallelo con un droke gratuito di Heroku, che ha un limite di 512 MB. Avere due lavoratori mi fa saltare il budget della memoria, e Heroku lo spegne. Ma ancora più importante, lo spreco di memoria come questo mi offende. – NeilK

+0

Um e pensi che non possa fare aritmetica, in realtà la struttura dati è 208 MB - 100 MB è stato un esempio – NeilK

+0

@NeilK Ma il limite di 512 MB non ti ha offeso? : D Inoltre: anche con il processo figlio di fork copia i dati a meno che non sia di sola lettura. – freakish

5

Ho provato a scrivere un binding C/C++ dell'accesso alla memoria condivisa da nodejs. https://github.com/supipd/node-shm

Ancora in corso (ma funziona per me), forse utile, se bug o suggerimento, informarmi.

+0

Questa è una grande idea @supipd, ma è possibile che tu stia lavorando alla versione corrente? Credo che 'node :: ObjectWrap' non sia collegato a' 'nelle versioni più recenti. (gli utenti riceveranno un errore durante la compilazione) Comunque, questa dovrebbe essere la risposta accettata. :) –

0

La maggior parte delle applicazioni Web trascorre la maggior parte della loro vita in attesa di buffer di rete e letture del database. Node.js è progettato per eccellere in questo lavoro rilegato. Se il tuo lavoro è veramente vincolato dalla CPU, potresti essere meglio servito da un'altra piattaforma.

Con quella di mezzo ...

  1. Usa process.nextTick (forse anche blocchi annidati) per assicurarsi che il lavoro costoso CPU è correttamente asincrona e non ha permesso di bloccare il tuo thread. Ciò assicurerà che un cliente che effettua richieste costose non abbia un impatto negativo su tutti gli altri.

  2. Utilizzare il cluster node.js per aggiungere un processo di lavoro per ogni CPU nel sistema. I processi di lavoro possono essere associati a un'unica porta HTTP e utilizzare Memcached o Redis per condividere lo stato della memoria. I lavoratori hanno anche un'API di messaggistica che può essere utilizzata per mantenere sincronizzata una memoria cache in-process, tuttavia presenta alcuni limiti di coerenza.

Problemi correlati