2013-04-06 22 views
5

So che è una domanda ricorrente e ho letto articoli come il seguente http://www.mailinator.com/tymaPaulMultithreaded.pdf dicendo che non è necessariamente vero che nio scala meglio di io.Quali sono i vantaggi di java.nio per un server web?

Ma non riesco a vedere come potrebbe java nio scalare meglio nello sviluppo di un server Web rispetto a un'architettura tradizionale dei thread accettatore/lavoratore? Mi spiego:

Di solito i server web Java utilizzano il seguente schema per gestire le connessioni:

  • A pochi fili accettore limitato al numero di core bloccare il metodo accept() del ServerSocket:

    while (true) { 
        socket = serverSocket.accept(); 
        // handleRequest submits the socket to a queue 
        handleRequest(socket); 
        socket.close(); 
    } 
    
  • Quando il socket client viene recuperato, viene inviato a una coda non bloccante e quindi elaborato da un thread di lavoro da un pool di thread di lavoro. Il numero di thread di lavoro in base alla durata delle operazioni io eseguite.

Come utilizzare java.nio renderebbe questa architettura più scalabile?

Voglio dire che avrei ancora bisogno di avere thread di lavoro per elaborare la richiesta che farebbe operazioni di blocco (accesso al database o al filesystem, invocazione di servizi esterni). Se le operazioni di back-end non vengono eseguite in modo asincrono come in node.js, avrei comunque bisogno di thread funzionanti che limitassero la scalabilità complessiva rispetto a 1 o 2 thread di dispatcher di eventi.

+0

NIO è più utile quando si hanno connessioni inattive di lunga durata. Quindi, ad esempio, un'applicazione che utilizza pesantemente il polling lungo sarebbe in grado di elaborare più richieste con NIO che con IO come con IO ogni blocco di collegamento a lungo polling e vincola un thread. Con NIO questo non è il caso. –

+0

Per ridurre i numeri di thread: più thread, più chiamate di sistema. – coolcfan

risposta

14

Mi piace molto l'articolo di Paul Tyma su questo argomento, è davvero approfondito. Mi piacerebbe vedere due punti principali nel suo articolo:

  • si può ottenere una maggiore velocità con la tradizionale, bloccando IO (misurò esso)
  • tradizionali, bloccando IO rende il vostro modo logica del server meno complessa - l'stato del dialogo client-server è implicitamente definito nel flusso del thread.

La ragione principale per uso non-blocking NIO è quando si hanno molte, molte simultanei, le richieste di inattività. Il motivo è: con NIO puoi servire più richieste dallo stesso thread, e questo è meglio.

Ok, questo è ciò che puoi leggere ovunque. Ora ... perché lo è il migliore?

Ci sono due motivi principali, che sono collegati a due diversi tipi di sovraccarico che vengono con ogni thread:

  • quando lo scheduler cambia il filo il processore sta eseguendo, c'è un "interruttore contesto", che può essere un'operazione costosa (cioè il thread ha uno stato nel processore - valori nei registri, tonnellate di dati caricati in cache L1, L2, L3, ecc. - che deve essere "salvato" da qualche parte quando il thread si ferma e "reloaded" quando il thread continua ad essere eseguito, inoltre, quando perdi il contenuto delle cache L1, L2, L3, avrai probabilmente un sacco di errori di cache, che potrebbero essere cattivi (o meno, dipende dal carico di lavoro))
  • ciascun filo deve assegnare un proprio, indipendente pila (che viene solitamente utilizzato per memorizzare le variabili locali e ritorno indirizzi delle chiamate di funzione)

Quindi, ogni filo viene con alcuni più "spreco" memoria e possibilmente " sprecato "cicli del processore (per eseguire il" cambio di contesto ").

Ora, supponiamo di avere un server di chat, i client effettuano connessioni HTTP richiedendo nuovi messaggi e il server risponderà solo quando ci sono nuovi messaggi per quel client (in modo che i client ricevano immediatamente nuovi messaggi). Supponiamo che tu abbia 10k tali clienti. Nel modello tradizionale di blocco thread-per-connessione, avresti 10k thread. In Java, un valore standard tipico per la dimensione dello stack di thread (-Xss) è 256kb. Con i thread 10k, stai utilizzando automaticamente circa 2 GB di memoria !!!!!!!! Peggio ancora: anche se non c'è alcuna attività sul tuo server di chat, nessun messaggio viene inviato, i client ti stanno ancora facendo perdere quei 2 GB. Aggiungi tonnellate di interruttori di contesto e vedi che hai un problema.

In questa situazione, sarebbe meglio utilizzare NIO non bloccante, in cui un numero inferiore di thread (eventualmente solo 1!) Sarebbe sufficiente per gestire tutti i client 10k, quindi è necessario salvare i selettori di contesto (ad esempio, tempo di cpu) e stack di thread (cioè memoria), anche a scapito di un codice più complesso, che di solito è un effetto collaterale dell'uso di NIO non bloccante.

+0

Aggiunta di link a [articolo di Paul Tyma] (http://paultyma.blogspot.sg/2008/03/writing-java-multithreaded-servers.html?m=1) per chi è interessato a leggere. – Misterhex

3

L'IO NIO o non bloccante può scalare molto bene per una concorrenza elevata, non è necessario un thread dedicato per ciascuna connessione, è sufficiente un solo thread principale per accettare le connessioni e alcuni thread di altri worker per gestire l'IO, il numero di thread è fisso e questo è il motivo principale per cui è più scalabile rispetto all'architettura tradizionale dei thread accettatore/lavoratore.

Problemi correlati