In diesem Artikel werden wir hauptsächlich die Probleme erläutern, die in der Asynchronverarbeitung von Servlet 3.0 in der Java -Entwicklung und den Lösungen auftreten. Das Folgende sind der spezifische Inhalt:
Servlet 3.0 hat begonnen, einen asynccontext zur Unterstützung der asynchronen Bearbeitung von Anforderungen bereitzustellen. Welche Vorteile können also eine asynchrone Bearbeitung von Anfragen bringen?
Im Allgemeinen ist die Art und Weise, wie Webcontainer Anforderungen behandeln, jeder Anforderung einen Thread zuzuweisen. Wir alle wissen, dass die Erstellung von Threads nicht ohne Kosten ist und der Thread -Pool der Webcontainer eine Obergrenze hat.
Ein sehr vorhersehbares Problem ist, dass unter hohen Lastbedingungen der Thread -Pool besetzt ist, sodass die anschließende Anfrage nur gewartet werden kann. Wenn Sie kein Glück haben, meldet der Kunde einen Wartezeitüberschreitungsfehler.
Bevor Asynccontext erschien, bestand die einzige Möglichkeit, dieses Problem zu lösen, den Thread -Pool des Webcontainers zu erweitern.
Aber es gibt immer noch ein Problem damit. Betrachten Sie die folgenden Szenarien:
Es gibt einen Webcontainer mit einer Thread-Poolgröße von 200. Es gibt eine Web-App mit zwei Servlets, die Zeit, die Servlet-A benötigt, um eine einzelne Anforderung zu verarbeiten, beträgt 10 Sekunden, und die Zeit, die Servlet-B benötigt, um eine einzelne Anforderung zu verarbeiten, beträgt 1s.
Jetzt begegnen wir auf eine hohe Last mit mehr als 200 Anfragen an Servlet-A. Wenn Servlet-B zu diesem Zeitpunkt angefordert wird, werden wir warten, da alle HTTP-Threads von Servlet-A besetzt sind.
Zu diesem Zeitpunkt entdeckte der Ingenieur das Problem und erweiterte die Gewindepoolgröße auf 400, aber die Last stieg weiter an. Jetzt gibt es 400 Anfragen an Servlet-A, und Servlet-B kann immer noch nicht antworten.
Hast du das Problem gesehen? Da HTTP-Thread und Worker-Thread miteinander gekoppelt sind, wird der HTTP-Thread ausgefüllt, wenn eine große Anzahl von Anforderungen an einen zeitaufwändigen Vorgang gestellt wird, was dazu führt, dass der gesamte Webcontainer nicht antworten kann.
Wenn wir Asynccontext verwenden, können wir den zeitaufwändigen Vorgang mit einem anderen Thread übergeben, damit der HTTP-Thread freigegeben wird und wir andere Anforderungen bearbeiten können.
Beachten Sie, dass nur die Verwendung von Asynccontext den oben genannten Effekt erzielen kann. Wenn Sie den neuen Thread () oder ähnliche Methoden direkt verwenden, wird der HTTP -Thread nicht an den Container zurückgegeben.
Hier ist ein offizielles Beispiel:
@Webervlet (urlpatterns = {"/asyncServlet"}, asyncSupported = true) AsyncServlet erweitert HttpServlet {/ * ... gleiche Variablen und Init -Methode wie in syncServlet ... */@override public void dotget (httpletretRect, httpletretRect, httpletretRect, httpletretRect, htttpletretRect, htttpletretRect. Antwort.SetContentType ("text/html; charSet = utf-8"); endgültig asynccontext acontext = request.StartAsync (); AconText.start (new Runnable () {public void run () {String param = acontext.getRequest (). getParameter ("param"); String result = Ressource.Process (param); }} fangen
In diesem offiziellen Beispiel öffnet jeder HTTP -Thread einen anderen Worker -Thread, um die Anforderung zu verarbeiten und dann den HTTP -Thread an den Webcontainer zurückzugeben. Schauen Sie sich jedoch den Javadoc der asynccontext.start () -Methode an:
Bewirkt, dass der Container einen Thread, möglicherweise aus einem verwalteten Thread -Pool, den angegebenen Runnable ausführt.
Tatsächlich gibt es hier keine Regulierung, aus der der Arbeiter -Thread stammt. Vielleicht ist es ein anderer Thread -Pool außer dem HTTP -Threadpool? Oder ist es nur ein HTTP -Threadpool?
Die begrenzte Nützlichkeit von Asynccontext.start () Artikel liest: Verschiedene Webcontainer haben dafür unterschiedliche Implementierungen, aber Tomcat verwendet tatsächlich den HTTP -Thread -Pool, um asynccontext.start () zu verarbeiten.
Dies bedeutet, dass wir ursprünglich den HTTP -Thread veröffentlichen wollten, aber tatsächlich nicht, da der HTTP -Thread immer noch als Worker -Thread verwendet wird, aber dieser Thread ist nicht mit dem HTTP -Thread, der die Anforderung empfängt.
Wir können diese Schlussfolgerung auch durch den JMeter -Benchmark von AsyncServlet1 und SyncServlet sehen, und die Ergebnisse der beiden Durchsatz sind ähnlich. Startmethode: Starten Sie Main und verwenden Sie dann JMeter, um Benchmark.jmx zu starten (HTTP -Threadpool = 200 unter Tomcat -Standardkonfiguration).
Verwenden von Executorservice
Ich habe früher gesehen, dass Tomcat den Arbeiter -Thread -Pool nicht separat beibehält. Daher müssen wir einen Weg finden, es selbst zu tun, siehe AsyncServlet2, das einen ExecutorService mit Thread -Pool verwendet, um Asynccontext zu verarbeiten.
Andere Wege
Daher gibt es keine feste Möglichkeit, Asynccontext zu verwenden. Sie können verschiedene Methoden anwenden, um sie entsprechend den tatsächlichen Bedürfnissen zu bewältigen. Aus diesem Grund benötigen Sie Kenntnisse über Java -gleichzeitige Programmierung.
Missverständnisse der Leistung
Der Zweck von Asynccontext besteht nicht darin, die Leistung zu verbessern, und es bietet auch keine Leistungsverbesserung. Es bietet einen Mechanismus, um HTTP -Thread- und Worker -Thread zu entkoppeln, wodurch die Reaktionsfähigkeit von Webcontainern verbessert wird.
Asynccontext kann jedoch irgendwann die Leistung verbessern, dies hängt jedoch davon ab, wie Ihr Code geschrieben wird.
Zum Beispiel: Die Anzahl der HTTP -Threadpools in einem Webcontainer beträgt 200, und ein Servlet verwendet einen 300 Worker -Thread -Pool, um asynccontext zu verarbeiten.
Im Vergleich zum Sync -Methode -Worker -Threadpool = HTTP -Threadpool = 200 haben wir in diesem Fall einen Arbeiter -Thread -Pool von 300, sodass er definitiv einige Leistungsverbesserungen mit sich bringt (schließlich arbeiten mehr Menschen).
Im Gegenteil, wenn die Anzahl der Worker -Threads <= die Anzahl der HTTP -Threads beträgt, gibt es keine Leistungsverbesserung, da der Engpass für die Bearbeitung von Anforderungen bei Worker -Thread liegt.
Sie können die Thread -Poolgröße von AsyncServlet2 ändern und mit SyncServlet -Benchmark -Ergebnissen vergleichen, um diese Schlussfolgerung zu überprüfen.
Denken Sie nicht, dass der Worker -Thread -Pool größer sein muss als der HTTP -Threadpool. Die Gründe sind wie folgt:
Die beiden Verantwortlichkeiten sind unterschiedlich. Eine davon ist, dass der Webcontainer verwendet wird, um externe Anforderungen zu empfangen , und das andere ist die Verarbeitung von Geschäftslogik.
Das Erstellen von Themen ist kostenlos. Wenn der HTTP -Thread -Pool bereits groß ist, führt das Erstellen eines größeren Worker -Thread -Pools zu viel Kontextschalter und Speicheraufwand.
Der Zweck von Asynccontext besteht darin, den HTTP-Thread freizugeben, um die langfristige Verwendung von Operationen zu vermeiden und so den Webcontainer nicht zu reagieren.
In den meisten Fällen ist der Arbeiter -Thread -Pool nicht sehr groß und verschiedene Arbeiter -Thread -Pools werden nach verschiedenen Unternehmen gebaut.
Zum Beispiel: Die Größe des Web -Container -Thread -Pools beträgt 200 und die Größe der Worker -Thread -Pool -Größe für ein langsames Servlet. Auf diese Weise werden unabhängig davon, wie viele Anfragen verwendet werden, um den Vorgang zu verlangsamen, den HTTP -Thread nicht auszufüllen und andere Anfragen nicht zu verarbeiten.