Analyse et résolution de la consommation mémoire excessive d'une application Spring Boot en environnement Docker

Tags associésï¼1.FAQ sur les erreurs de docker login, docker push et docker pull
2.Comment installer Docker sur Ubuntu 20

Introduction à Spring Boot

Une application Spring Boot simple, utilisée par un seul utilisateur, atteint 1,2 Go de mémoire, ce qui est excessif.

Consommation mémoire excessive d'une application Spring Boot


Une application Spring Boot simple, utilisée par un seul utilisateur, atteint 1,2 Go de mémoire, ce qui est excessif.
État des services

Le nombre de services étant réduit et les ressources serveur suffisantes, de nombreux services ont été démarrés sans paramètres JVM (problèmes hérités). Résultat : chaque démarrage de service consomme entre 1,2 Go et 2 Go de mémoire, alors que certains services n'ont pas besoin d'autant. Comment la mémoire JVM est-elle configurée dans Spring Boot lorsque le paramètre de mémoire JVM n'est pas défini ?

Paramètres de mémoire JVM par défaut de Spring Boot


Lors de l'exécution d'un projet Spring Boot, si le paramètre de mémoire JVM n'est pas défini, Spring Boot utilise la stratégie de configuration par défaut de la JVM. Lorsque les ressources sont suffisantes, les développeurs ne se soucient guère des paramètres de mémoire. Mais en cas de pénurie de ressources ou d'optimisation de la JVM, il est essentiel de comprendre la stratégie de configuration mémoire par défaut.
Les paramètres les plus courants concernant la mémoire JVM sont la taille initiale du tas (- Xms ) et la taille maximale du tas (- Xmx ). Beaucoup ne prennent pas la peine de les définir et utilisent les valeurs par défaut de la JVM. En particulier dans l'environnement de développement, si de nombreux microservices sont démarrés, la mémoire peut saturer.

Spring Boot.La stratégie de configuration mémoire par défaut de la JVM se divise en deux scénarios : un scénario avec un espace mémoire important et un scénario avec un espace mémoire réduit (moins de 192 Mo).
Prenons l'exemple d'une mémoire de 4 Go : la taille initiale et la taille maximale du tas sont les suivantes :

Spring Boot.Par défaut, la taille maximale du tas occupe 1/4 de la mémoire physique. Si l'application dépasse cette limite, une exception OutOfMemoryError est levée. La taille initiale du tas est de 1/64 de la mémoire physique.
Si l'application s'exécute sur un téléphone mobile ou si la mémoire physique est inférieure à 192 Mo, les tailles initiale et maximale du tas par défaut de la JVM sont les suivantes :

La taille maximale du tas est égale à 1/2 de la mémoire physique et la taille initiale du tas à 1/64 de la mémoire physique, avec un minimum de 8 Mo pour la taille initiale.

Lorsque la mémoire libre du tas par défaut est inférieure à 40 %, la JVM augmente le tas jusqu'à la limite maximale de - Xmx ; lorsque la mémoire libre du tas est supérieure à 70 %, la JVM réduit le tas jusqu'à la limite minimale de - Xms .
Par conséquent, le serveur définit généralement -Xms et -Xmx à la même valeur pour éviter le redimensionnement du tas après chaque GC. La mémoire du tas d'un objet est récupérée par un système de gestion automatique de la mémoire appelé le garbage collector.

La taille maximale du tas représente la limite supérieure de la mémoire utilisée par la JVM. En cours d'exécution, la mémoire consommée correspond à la quantité effectivement utilisée. Par défaut, l'espace maximal alloué à la jeune génération est égal à un tiers de la taille totale du tas.

Spring Boot.Pour résoudre le problème initial, si chaque programme démarre avec la configuration par défaut et que plusieurs applications sont déployées sur un même serveur, la mémoire viendra à manquer, entraînant un gaspillage. L'opération la plus simple consiste à ajouter les paramètres de mémoire JVM correspondants lors du démarrage avec java -jar.
java -Xms64m -Xmx128m -jar xxx.jar
Le projet utilise un déploiement Docker. Examinons d'abord le fichier Dockerfile d'origine.

EXPOSE 8061

ADD target/certif-system-2.1.0.jar /certif-system-2.1.0.jar

ENTRYPOINT ["java", "-jar","/certif-system-2.1.0.jar"]

Optimisation de Spring Boot
Limiter la mémoire JVM

Spring Boot transmet toutes les variables d'environnement à l'application, mais notre variable JAVA_OPTS ne s'adresse pas à l'application elle-même, elle s'adresse au runtime Java. Il faut donc utiliser la variable $JAVA_OPTS avec exec java. Cela nécessite quelques modifications mineures du Dockerfile :
ENTRYPOINT exec java $JAVA_OPTS -jar app.jar
Exécuter la commande docker run
Cela signifie que les informations du paramètre JAVA_OPTS dans la variable d'environnement sont remplacées par la réinitialisation via -e au moment de l'exécution.
docker run -e JAVA_OPTS='-Xmx1344M -Xms1344M -Xmn448M - XX:MaxMetaspaceSize =192M - XX:MetaspaceSize =192M'

Rôle de java.security.egd
SecureRandom est largement utilisé dans les différents composants de Java et permet de générer des nombres aléatoires de manière fiable. Toutefois, dans les scénarios où un grand nombre de nombres aléatoires sont générés, les performances peuvent se dégrader. Dans ce cas, vous pouvez utiliser "- Djava.security.egd =file:/dev/./ urandom " pour accélérer le processus de génération de nombres aléatoires.
Il est recommandé de spécifier le générateur de nombres aléatoires /dev/./urandom lorsque vous utilisez un grand nombre de nombres aléatoires.
Veuillez prêter attention à la quatrième ligne du code source ci-après pour identifier la cause du bug. Si le paramètre java.security.egd spécifie file:/dev/random ou file:/dev/urandom, le constructeur NativeSeedGenerator sans paramètre est appelé, et ce constructeur sans paramètre utilise file:/dev/random par défaut. Le code d'OpenJDK est différent de celui de HotSpot. OpenJDK n'utilise pas cette variable lors de la génération ultérieure de nombres aléatoires.

Articles associés

Découvrir plus d'offres spéciales

  1. Short Message Service (SMS) et Service de messagerie

    50,000 email package starts as low as USD 1.99, 120 short messages start at only USD 1.00

phone Contacter
Hi, I'm Alibaba Cloud AI Assistant!
I can help with questions and solutions.