J'ai un comportement étrange sur notre application Spring Boot:
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é:
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.
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.
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.
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.
Ce que vous décrivez est l'effet typique d'un redémarrage sur une infrastructure qui utilise un pool de connexions DB lourd.
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: