Raisons de l’utilisation élevée du processeur dans SocketInputStream.socketRead0 ()

Tout en profilant une application Web locale, je suis tombé sur une observation très étrange (du moins pour moi).

Presque tout le temps est passé dans la méthode socketRead0() d’une classe SocketInputStream . Ce n’est pas surprenant car mon application fait une mise en réseau avec un service distant sur chaque requête. Ce qui est étrange, c’est que non seulement l’utilisation de l’ heure de l’horloge murale est élevée pour cette méthode, mais que l’heure de l’horloge du processeur est également très élevée. Je ne peux pas comprendre pourquoi le temps CPU est élevé, car si mon application attend que le service distant réponde (ce qui n’est pas si rapide en fait), il n’y a plus rien à faire pour l’application elle-même. Le temps de calcul devrait donc être faible.

Un peu plus d’observation:

  • VisualVM en mode d’échantillonnage montre que la méthode SocketInputStream.socketRead0() consum jusqu’à 95% du temps (heure d’horloge murale et temps CPU);
  • mpstat (nous utilisons Linux comme système d’exploitation) affiche environ ~ 90% de temps utilisateur et ~ 1-3% de temps système (le rest est du temps d’inactivité);
  • application déployée sur le serveur dédié;
  • Le service à distance est une application Web HTTP également. Le temps de réponse moyen est d’environ 100 ms. La taille de réponse moyenne est d’environ 2 Ko.
  • mon application utilise spring RestTemplate pour interagir avec le service distant, pas directement avec SocketInputStream .

Pour le moment, je n’ai qu’une idée: peut-être qu’il s’agit d’appeler des méthodes natives dans JVM ( SocketInputStream.socketRead0() est natif)?

Qu’est-ce que tu penses? Y a-t-il d’autres raisons à cela?

VisualVM affiche load non comme une valeur absolue mais comme une valeur relative, ce qui signifie simplement que votre application n’a plus de sharepoint consommation de CPU.

Je pense que vous devez configurer VisualVM pour ne pas explorer en profondeur cette méthode et plutôt compter cet appel de méthode dans le cadre d’une méthode qui se trouve dans votre code (ou dans votre code).

J’ai déjà expérimenté un tel comportement, mais cela ne semblait pas nécessiter d’optimisation. L’application Web doit simplement lire les données des sockets (c.-à-d. Requête HTTP, firebase database, services réseau internes …) et cela ne l’aide pas.

Je suis confronté au même problème. Mon application a un qps très élevé et chaque requête me fera envoyer plusieurs appels d’épargne, qui utilisent cet api natif: socketRead0

Je décide donc de faire une expérience. Je fais un serveur simulé avec un api dormir 30 secondes avant le retour et un client appelle cette API. Mon but est de tester le statut du thread lorsque le net se passe. Basé sur mon vidage de thread, le statut du thread est RUNNABLE .

Cela explique deux choses:

  1. une application avec un blocage élevé du qps fera face à une valeur de charge élevée du processeur

  2. votre thread Java est toujours en cours d’exécution dans jvm, car l’état du thread est RUNNABLE ce qui consortingbuera à une utilisation élevée de l’unité centrale de l’espace utilisateur

Ces deux choses vont occuper votre processeur.

J’ai remarqué pendant l’expérience que l’utilisation de l’unité centrale de l’espace système était faible. Je pense que ceci est lié à la différence de stratégie de planification des threads entre jvm et os. Nous soaps que le modèle de thread de hotspot est 1: 1, ce qui signifie un thread jvm à un thread os. Quand un blocage se produit, comme socketRead0 le thread du kernel définit S et ne bloque pas cpu, mais le thread de l’espace utilisateur bloque (en attente). Lorsque cela s’est produit, je pense que nous devons repenser le modèle d’E / S fondamental dans notre application.