Grâce à cet article, nous expliquerons principalement les problèmes rencontrés dans le traitement asynchrone du servlet 3.0 dans le développement Java et les solutions. Voici le contenu spécifique:
Servlet 3.0 a commencé à fournir AsyncConText pour prendre en charge le traitement asynchrone des demandes. Alors, quels avantages le traitement asynchrone des demandes peut-il apporter?
D'une manière générale, la façon dont les conteneurs Web gèrent les demandes d'attribution d'un thread à chaque demande. Nous savons tous que la création de threads n'est pas sans coût et que le pool de fils de conteneurs Web a une limite supérieure.
Un problème très prévisible est que dans des conditions de charge élevée, le pool de threads est occupé, de sorte que la demande suivante ne peut être attendue que. Si vous n'êtes pas chanceux, le client rapportera une erreur de temps d'attente.
Avant que AsyncConText n'apparaisse, la seule façon de résoudre ce problème était d'étendre le pool de threads du conteneur Web.
Mais il y a toujours un problème avec cela, considérez les scénarios suivants:
Il y a un conteneur Web avec une taille de pool de threads de 200. Il existe une application Web qui a deux servlets, le temps qu'il faut servlet-A pour gérer une seule demande est de 10s, et le temps qu'il faut servlet-B pour gérer une seule demande est de 1 s.
Maintenant, nous rencontrons une charge élevée, avec plus de 200 demandes à Servlet-A. Si Servlet-B est demandé pour le moment, nous attendrons car tous les threads HTTP ont été occupés par Servlet-A.
À ce moment, l'ingénieur a découvert le problème et étendu la taille du pool de filetage à 400, mais la charge a continué à augmenter. Maintenant, il y a 400 demandes à Servlet-A, et Servlet-B ne peut toujours pas répondre.
Avez-vous vu le problème? Étant donné que le thread HTTP et le thread de travailleur sont couplés ensemble, il remplira le thread HTTP lorsqu'un grand nombre de demandes sont effectuées sur une opération longue, ce qui entraîne la réponse à l'ensemble du conteneur Web.
Cependant, si nous utilisons AsyncConText, nous pouvons remettre l'opération de longue date vers un autre thread, afin que le thread HTTP soit libéré et que nous pouvons gérer d'autres demandes.
Notez que l'utilisation uniquement d'AsyncConText peut réaliser l'effet mentionné ci-dessus. Si vous utilisez directement un nouveau thread () ou des méthodes similaires, le thread HTTP ne sera pas renvoyé dans le conteneur.
Voici un exemple officiel:
@Webservlet (urlpatterns = {"/ asyncservlet"}, asyncSupported = true) classe publique AsyncServlet étend httpservlet {/ * ... même variables et méthode init que dans SyncServlet ... * / @Override public Void Doget) Response.SetContentType ("Text / HTML; charSet = UTF-8"); Final asyncConText acontext = request.startasync (); acontext.start (new Runnable () {public void run () {string param = acontext.getRequest (). getParameter ("param"); string result = Resource.Process (param); httpservletResponse réponse = acontext.getResponse (); / * ... imprimer à la réponse ... * / acontext.Plelete ();}}); }} piège
Dans cet exemple officiel, chaque thread HTTP ouvrira un autre thread de travailleur pour traiter la demande, puis renverra le thread HTTP dans le conteneur Web. Mais regardez le javadoc de la méthode asyncConText.start ():
Faire enfiler le conteneur un thread, peut-être à partir d'un pool de threads géré, exécuter le runnable spécifié.
En fait, il n'y a pas de règlement ici d'où vient le fil du travailleur. Peut-être que c'est une autre piscine de threads autres que la piscine de thread HTTP? Ou est-ce juste un pool de thread HTTP?
L'utilité limitée de l'article asyncConText.Start () se lit comme suit: Différents conteneurs Web ont des implémentations différentes pour cela, mais Tomcat utilise en fait le pool de threads HTTP pour gérer AsyncConText.Start ().
Cela signifie que nous voulions à l'origine libérer le thread HTTP, mais en fait, ce n'est pas le cas, car le thread HTTP est toujours utilisé comme thread de travailleur, mais ce thread n'est pas le même que le thread HTTP recevant la demande.
Nous pouvons également voir cette conclusion à travers la référence JMeter d'AsyncServlet1 et SyncServlet, et les résultats du débit de deux sont similaires. Méthode de démarrage: Démarrez Main, puis utilisez JMeter pour démarrer Benchmark.jmx (HTTP Thread Pool = 200 sous la configuration par défaut de Tomcat).
Utilisation de l'exécution
J'ai vu plus tôt que Tomcat ne maintient pas la piscine de threads de travailleur séparément, nous devons donc trouver un moyen de le faire nous-mêmes, voir AsyncServlet2, qui utilise un exécuteur exécutif avec un pool de threads pour gérer AsyncConText.
Autres façons
Par conséquent, il n'y a pas de moyen fixe d'utiliser AsyncConText. Vous pouvez utiliser différentes méthodes pour y faire face en fonction des besoins réels. Pour cette raison, vous avez besoin d'une certaine connaissance de la programmation concurrente Java.
Malentendu de performance
Le but d'AsyncContext n'est pas d'améliorer les performances, et il ne fournit pas directement une amélioration des performances. Il fournit un mécanisme pour découpler le thread HTTP et le thread de travail, améliorant ainsi la réactivité des conteneurs Web.
Cependant, AsyncConText peut améliorer les performances à un moment donné, mais cela dépend de la façon dont votre code est écrit.
Par exemple: le nombre de pools de threads HTTP dans un conteneur Web est de 200, et un servlet utilise un pool de threads de travail 300 pour gérer AsyncConText.
Par rapport à la méthode Sync Worker Thread Pool = HTTP Thread Pool = 200, dans ce cas, nous avons un pool de threads de travail de 300, donc cela apportera certainement des améliorations de performances (après tout, il y a plus de personnes qui travaillent).
Au contraire, si le nombre de threads de travailleur est <= le nombre de threads HTTP, il n'y aura pas d'amélioration des performances, car le goulot d'étranglement pour les demandes de traitement est au fil du travailleur.
Vous pouvez modifier la taille du pool de threads d'AsyncServlet2 et le comparer avec les résultats de référence SyncServlet pour vérifier cette conclusion.
Ne pensez pas que le pool de threads de travailleur doit être plus grand que le pool de thread HTTP. Les raisons sont les suivantes:
Les deux responsabilités sont différentes. L'une est que le conteneur Web est utilisé pour recevoir des demandes externes , et l'autre consiste à traiter la logique métier.
La création de fils a un coût. Si le pool de threads HTTP est déjà grand, la création d'un pool de threads de travail plus grand provoquera trop de commutateurs de contexte et de surcharge de mémoire.
Le but d'AsyncConText est de libérer le thread HTTP pour éviter l'utilisation à long terme des opérations et, ce qui fait que le conteneur Web ne peut pas répondre.
Donc, dans la plupart des cas, le pool de threads de travailleur ne sera pas très grand et différents pools de fil de travail seront construits selon différentes entreprises.
Par exemple: la taille du pool de threads de conteneur Web est de 200, et la taille du pool de threads de travail est de 10 pour un servlet lent. De cette façon, peu importe le nombre de demandes utilisées pour ralentir les opérations, elle ne remplira pas le thread HTTP et ne fera pas de traitement d'autres demandes.