web-dev-qa-db-fra.com

Performances - Spring Boot - Temps de réponse du serveur

J'ai un comportement étrange sur notre application Spring Boot:

  • Frontend/Client - angular 6
  • Backend - Spring Boot - Spring MVC - Tomcat intégré - Linux

Après avoir redémarré le backend, les premiers appels à un contrôleur nécessitent environ 5 secondes, la même demande suivante ne prend que 50 ms. Ceci est reproductible dans 90% des cas, parfois même le premier appel est rapide.

Je suis sûr que le problème est sur le serveur et non sur le client. Sur le navigateur, je vois que le temps TTFB (temps jusqu'au premier octet) augmente à 5 secondes. Les requêtes suivantes n'ont besoin que de 10 ms pour TTFB.

Avec des outils de surveillance sur le serveur (dynamique des applications), je peux collecter ces appels de serveur lents et sur le graphique des appels, je peux voir que:

org.Apache.catalina.webresources.JarWarResourceSet:getArchiveEntries:117

a besoin de 4916 ms. Voici donc mon goulot d'étranglement, je pense. Mais je ne sais pas comment y remédier.

Ce que j'ai déjà essayé:

  • Passé de hikaricp au pool de connexions Apache Tomcat jdbc
  • Botte de printemps améliorée de 2.0.0 à 2.0.5
  • Mise à niveau Java à 1.8.0_181
  • Propriété spring.jpa.Tomcat.testOnBorrow = true
  • Propriété spring.jpa.Tomcat.validationQuery = sélectionnez 1

Tout sans influence sur le délai du serveur.

Mise à jour

Le temps est perdu car le fichier de guerre est analysé plusieurs fois.

org.Apache.catalina.webresources.CachedResource.validateResource vérifie si nous avons un fichier de guerre ( isPackedWarFile ) et cette vérification retourne faux. Même s'il s'agit d'un fichier de guerre. Pour cette mauvaise conduite, j'ai une solution de contournement. J'ai défini Tomcat.resource.cache-tt sur une valeur élevée.

Mais maintenant org.Apache.catalina.webresources.Cache.getResource a un noCache méthode. Et dans cette méthode les fichiers classe et jar sont exclus de la mise en cache. Et c'est la raison pour laquelle le fichier de guerre est à nouveau analysé.

L'analyse de l'ensemble du fichier de guerre prend environ 5 secondes. Et cette pause est un arrêt de la rupture du monde. Et cette analyse est absolument inutile car le fichier de guerre n'est pas explosé et son contenu ne peut donc pas être modifié.

Mise à jour

Si je mets le fichier war dans une installation Tomcat, tout est rapide. Le Tomcat intégré est le problème.

13
tomas

Je suppose que vous l'avez déjà fait, mais si ce n'est pas le cas, jetez un œil à https://wiki.Apache.org/Tomcat/HowTo/FasterStartUp et implémentez les correctifs suggérés.

Pour désactiver la numérisation avec Tomcat intégré, il y a une suggestion dans les commentaires ici https://github.com/spring-projects/spring-boot/issues/161

Si aucune des suggestions ci-dessus ne vous aide à corriger le retard, une solution de contournement possible serait de faire cette première demande au démarrage du serveur (et de déclencher le retard à partir de là).

@SpringBootApplication
public class Application implements CommandLineRunner {

    @Autowired
    private RestTemplate template;

    public static void main (String args[]){
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void run(String... strings) throws Exception {
        // do an initial request from here to trigger scanning the war
        template.exchange(...);
    }

}

De cette façon, votre client ne subira plus le délai de 5 secondes. Je suis conscient que c'est un hack, donc si vous trouvez un moyen plus propre de le faire, utilisez-le à la place.

3
user10367961

J'étais confronté à un problème similaire d'utilisation élevée du processeur et de retard de réponse. org.Apache.catalina.webresources.JarWarResourceSet:getArchiveEntries prenait environ 5 secondes lors de la numérisation du fichier de guerre. Pendant la numérisation, aucune demande n'a été traitée.

J ai mis a jour Spring boot version de 1.4.2.RELEASE à 1.5.12.RELEASE, qui a résolu ce problème. En effet, il semble que le problème soit avec le Tomcat intégré qui a été corrigé dans les versions ultérieures.

1
Naveen Katiyar

L'utilisation d'un fichier exécutable [~ # ~] jar [~ # ~] (au lieu d'un WAR) pour fonctionner avec Tomcat intégré a résolu le problème pour moi. C'est la méthode recommandée pour accélérer le chargement des ressources à partir des archives exécutables.

  1. vous pouvez avoir n projet Spring Boot et déployer sur JAR ou WAR ,
  2. J'ai dû passer de WAR à JAR pour avoir de meilleures performances et j'ai eu un problème lors de l'utilisation des balises JSP dans freemarker. C'est n moyen de résoudre ce problème lors de l'utilisation des balises JSP .
0
rochb

Ce que vous décrivez est l'effet typique d'un redémarrage sur une infrastructure qui utilise un pool de connexions DB lourd.

  • première demande: ouvrir la connexion physique (100 ms à 2 à 3 secondes), effectuer une initialisation (dépend de la base de données), exécuter SQL (varier selon la requête), revenir au pool (<1 ms)
  • deuxième requête: extraire du pool (<1 ms), exécuter SQL (varier selon la requête), revenir au pool (<1 ms)

sur la base de vos données, ma meilleure supposition est que les deux premières étapes sont lentes et que le pool de bases de données est réchauffé, vous rencontrerez des requêtes très lentes. Les améliorations potentielles sont les suivantes:

  • configurer une période de préchauffage au cours de laquelle le pool effectue une auto-initialisation pendant que Tomcat ne répond pas encore
  • vérifier du côté de la base de données ce qui est fait lors de la création de la connexion et du côté de l'application si/quelle configuration vous devez configurer la connexion
0
Simone Avogadro