2013-04-06 11 views
5

Ich weiß, es regelmäßig wieder Frage ist, und ich habe Artikel gelesen wie die folgenden http://www.mailinator.com/tymaPaulMultithreaded.pdf sagte, dass als io nicht unbedingt wahr, dass nio Skalen besser ist.Welche Vorteile bietet java.nio für einen Webserver?

aber ich bin kämpfen, um zu sehen, wie nio Skalen besser java könnte, wenn ein Web-Server als eine herkömmliche Akzeptor/Worker-Threads Architektur zu entwickeln? Lassen Sie mich erklären:

Normalerweise Java-Web-Server verwenden das folgende Muster Verbindungen zu handhaben:

  • Einige Akzeptor-Fäden auf die Anzahl der Kerne auf dem akzeptieren die ServerSocket- Block begrenzt() -Methode:

    while (true) { 
        socket = serverSocket.accept(); 
        // handleRequest submits the socket to a queue 
        handleRequest(socket); 
        socket.close(); 
    } 
    
  • Wenn das Client-Socket abgerufen wird er in eine nicht blockierende Warteschlange übermittelt wird und dann von einem Arbeiter-Thread aus einem Pool von Arbeitsthreads verarbeitet. Die Anzahl der Worker-Threads hängt von der Dauer der ausgeführten io-Vorgänge ab.

Wie java.nio verwenden würde diese Architektur skalierbarer machen?

Ich meine, ich würde noch Worker-Threads haben müssen, um die Anforderung zu verarbeiten, die Sperrung Operationen tun würde (Access-Datenbank oder Dateisystem, rufen Sie externe Dienste). Wenn die Back-End-Vorgänge nicht wie in node.js asynchron durchgeführt werden, würde ich immer noch bearbeitete Threads benötigen, die die Gesamt-Skalierbarkeit im Vergleich zu 1 oder 2 Event-Dispatcher-Threads einschränken würden.

+0

NIO ist sinnvoller, wenn Sie lange im Leerlauf befindliche Verbindungen haben. So könnte beispielsweise eine Anwendung, die lange Abfragen in Anspruch nimmt, mehr Anfragen mit NIO als mit IO verarbeiten können, da bei jeder langen Abfrageverbindung ein Thread blockiert und gebunden wird. Bei NIO ist dies nicht der Fall. –

+0

Um die Thread-Nummern zu reduzieren - mehr Threads, mehr Systemaufrufe. – coolcfan

Antwort

14

ich wie Paul Tyma Artikel über dieses Thema wirklich, es ist wirklich in der Tiefe. Ich würde zwei Hauptpunkte in seinem Artikel:

  • Sie eine besseren Durchsatz mit traditionellem bekommen können, Sperrung IO (er es gemessen)
  • traditionelle, IO blockiert macht Ihre Serverlogik Weise weniger komplex - die Der Status des Client-Server-Dialogs ist im Thread-Ablauf implizit definiert.

Der Hauptgrund, nicht blockierende NIO ist zu verwenden, wenn Sie viele gleichzeitige, Leerlauf-Anforderungen viele haben. Der Grund dafür ist: Mit NIO können Sie mehrere Anfragen aus dem gleichen Thread bedienen, und das ist besser.

Ok, das ist, was man überall lesen kann. Jetzt ... warum ist das besser?

Es gibt zwei Hauptgründe, die auf zwei verschiedene Arten von Kopf verbunden sind, die mit jedem Thread kommen:

  • , wenn der Scheduler den Faden ändert der Prozessor ausgeführt wird, gibt es einen „Kontextwechsel“, die kann eine teure Operation sein (dh der Thread hat einen Zustand im Prozessor - Werte in den Registern, Tonnen von Daten in L1-, L2-, L3-Caches usw.), die irgendwo "gespeichert" werden müssen, wenn der Thread aufhört und "neu geladen", wenn der Thread weiter ausgeführt wird, und wenn Sie den Inhalt von L1-, L2-, L3-Caches verlieren, erhalten Sie möglicherweise Tonnen von Cache-Fehlern, die schlecht sein können (oder nicht, hängt von der Auslastung ab))
  • jeder Thread hat seinen eigenen, unabhängigen Stapel (die lokalen Variablen zu speichern, verwendet wird, in der Regel und Rücksprungadressen von Funktionsaufrufen) zuzuteilen

Also, jeder Faden kommt mit etwas mehr „verschwendete“ Speicher und möglicherweise " verschwendete "Prozessorzyklen (um den" Kontextwechsel "auszuführen).

Nehmen wir an, Sie haben einen Chat-Server, die Clients stellen HTTP-Verbindungen für neue Nachrichten her und Ihr Server antwortet nur, wenn neue Nachrichten an diesen Client gesendet werden (damit Clients sofort neue Nachrichten erhalten). Angenommen, Sie haben 10k solcher Kunden. Im herkömmlichen, blockierenden Thread-pro-Verbindung-Modell hätten Sie 10k-Threads. In Java ist ein typischer Standardwert für die Threadstapelgröße (-Xss) 256 KB. Mit 10k Threads verwendest du automatisch ungefähr 2GB Speicher !!!!!!!! Schlimmer noch: Selbst wenn auf Ihrem Chat-Server überhaupt keine Aktivitäten stattfinden, keine Nachrichten gesendet werden, machen Sie die Clients immer noch damit fertig, diese 2 GB zu verschwenden. Fügen Sie Tonnen von Kontextwechsel hinzu, und Sie sehen, dass Sie ein Problem haben.

In dieser Situation wäre es besser, nicht blockierende NIO zu verwenden, bei der weniger Threads (eventuell nur 1!) Ausreichen würden, um alle 10k-Clients zu verarbeiten. CPU-Zeit) und Thread-Stacks (dh Speicher), selbst auf Kosten eines komplexeren Codes, was normalerweise ein Nebeneffekt der Verwendung von nicht-blockierendem NIO ist.

+0

Hinzufügen von Link zu [Paul Tymas Artikel] (http://paultyma.blogspot.sg/2008/03/writing-java-multithreaded-servers.html?m=1) für Interessierte zum Lesen. – Misterhex

3

NIO oder nicht-blockierende IO sehr gut für hohe Parallelität skaliert werden kann, können Sie nicht über einen dedizierten Thread für jede Verbindung benötigen, brauchen Sie nur einen Haupt-Thread-Verbindungen zu akzeptieren und ein paar andere Worker-Threads müssen IO handhaben, Die Anzahl der Threads ist fest und dies ist der Hauptgrund, warum sie skalierbarer ist als die traditionelle Architektur der Acceptor/Worker-Threads.