GNU/Linux >> Tutoriels Linux >  >> Linux

Utilisation élevée du processeur mais faible charge moyenne

Solution 1 :

Sous Linux au moins, la charge moyenne et l'utilisation du processeur sont en fait deux choses différentes. La charge moyenne est une mesure du nombre de tâches en attente dans une file d'attente d'exécution du noyau (pas seulement le temps CPU mais aussi l'activité du disque) sur une période de temps. L'utilisation du processeur est une mesure de l'occupation actuelle du processeur. La charge maximale qu'un seul thread CPU fixé à 100 % pendant une minute peut "contribuer" à la moyenne de charge sur 1 minute est de 1. Un processeur à 4 cœurs avec hyperthreading (8 cœurs virtuels) tous à 100 % pendant 1 minute contribuerait 8 à la charge moyenne sur 1 minute.

Souvent, ces deux nombres ont des modèles qui se corrèlent, mais vous ne pouvez pas les considérer comme identiques. Vous pouvez avoir une charge élevée avec une utilisation du processeur de près de 0 % (par exemple, lorsque vous avez beaucoup de données d'E/S bloquées dans un état d'attente) et vous pouvez avoir une charge de 1 et 100 % du processeur, lorsque vous avez un seul processus threadé en cours d'exécution. inclinaison complète. De plus, pendant de courtes périodes, vous pouvez voir le processeur à près de 100 %, mais la charge est toujours inférieure à 1, car les métriques moyennes n'ont pas encore "rattrapé".

J'ai vu un serveur avoir une charge de plus de 15 000 (oui vraiment ce n'est pas une faute de frappe) et un % CPU de près de 0 %. Cela s'est produit parce qu'un partage Samba avait des problèmes et que de nombreux clients ont commencé à rester bloqués dans un état d'attente d'E/S. Il y a de fortes chances que si vous voyez un nombre de charge élevé régulier sans activité CPU correspondante, vous rencontrez un problème de stockage quelconque. Sur les machines virtuelles, cela peut également signifier qu'il existe d'autres VM en concurrence pour les ressources de stockage sur le même hôte VM.

Une charge élevée n'est pas nécessairement une mauvaise chose, la plupart du temps, cela signifie simplement que le système est utilisé à sa pleine capacité ou qu'il est peut-être au-delà de sa capacité à suivre (si le nombre de charge est supérieur au nombre de cœurs de processeur). À un endroit où j'étais administrateur système, ils avaient quelqu'un qui surveillait la charge moyenne sur leur système principal de plus près que Nagios. Lorsque la charge était élevée, ils m'appelaient 24 heures sur 24, 7 jours sur 7, plus rapidement que vous ne pourriez dire SMTP. La plupart du temps, rien n'allait vraiment, mais ils associaient le numéro de chargement à quelque chose qui n'allait pas et le surveillaient comme un faucon. Après vérification, ma réponse était généralement que le système faisait juste son travail. Bien sûr, c'était au même endroit où la charge dépassait 15 000 (pas le même serveur cependant), donc parfois cela signifie que quelque chose ne va pas. Vous devez considérer le but de votre système. S'il s'agit d'un bourreau de travail, attendez-vous à ce que la charge soit naturellement élevée.

Solution 2 :

La charge est un nombre très trompeur. Prenez-le avec un grain de sel.

Si vous générez de nombreuses tâches en succession très rapide qui se terminent très rapidement, le nombre de processus dans la file d'attente d'exécution est trop petit pour enregistrer la charge pour eux (le noyau compte la charge une fois toutes les cinq secondes).

Considérez cet exemple, sur mon hôte qui a 8 cœurs logiques, ce script python enregistrera une grande utilisation du processeur en haut (environ 85 %), mais pratiquement aucune charge.

import os, sys

while True:
  for j in range(8):
    parent = os.fork()
    if not parent:
      n = 0
      for i in range(10000):
        n += 1
      sys.exit(0)
  for j in range(8):
    os.wait()

Autre implémentation, celle-ci évite wait par groupes de 8 (ce qui fausserait le test). Ici, le parent essaie toujours de maintenir le nombre d'enfants au nombre de processeurs actifs, de sorte qu'il sera beaucoup plus occupé que la première méthode et, espérons-le, plus précis.

/* Compile with flags -O0 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <err.h>
#include <errno.h>

#include <sys/signal.h>
#include <sys/types.h>
#include <sys/wait.h>

#define ITERATIONS 50000

int maxchild = 0;
volatile int numspawned = 0;

void childhandle(
    int signal)
{
  int stat;
  /* Handle all exited children, until none are left to handle */
  while (waitpid(-1, &stat, WNOHANG) > 0) {
    numspawned--;
  }
}

/* Stupid task for our children to do */
void do_task(
    void)
{
  int i,j;
  for (i=0; i < ITERATIONS; i++)
    j++;
  exit(0);
}

int main() {
  pid_t pid;

  struct sigaction act;
  sigset_t sigs, old;

  maxchild = sysconf(_SC_NPROCESSORS_ONLN);

  /* Setup child handler */
  memset(&act, 0, sizeof(act));
  act.sa_handler = childhandle;
  if (sigaction(SIGCHLD, &act, NULL) < 0)
    err(EXIT_FAILURE, "sigaction");

  /* Defer the sigchild signal */
  sigemptyset(&sigs);
  sigaddset(&sigs, SIGCHLD);
  if (sigprocmask(SIG_BLOCK, &sigs, &old) < 0)
    err(EXIT_FAILURE, "sigprocmask");

  /* Create processes, where our maxchild value is not met */
  while (1) {
    while (numspawned < maxchild) {
      pid = fork();
      if (pid < 0)
        err(EXIT_FAILURE, "fork");

      else if (pid == 0) /* child process */
        do_task();
      else               /* parent */
        numspawned++;
    }
    /* Atomically unblocks signal, handler then picks it up, reblocks on finish */
    if (sigsuspend(&old) < 0 && errno != EINTR)
      err(EXIT_FAILURE, "sigsuspend");
  }
}

La raison de ce comportement est que l'algorithme passe plus de temps à créer des processus enfants qu'à exécuter la tâche réelle (en comptant jusqu'à 10 000). Les tâches qui ne sont pas encore créées ne peuvent pas être prises en compte dans l'état "exécutable", mais occuperont %sys sur le temps CPU lorsqu'elles seront générées.

Ainsi, la réponse pourrait vraiment être dans votre cas que tout travail effectué génère un grand nombre de tâches en succession rapide (threads ou processus).

Solution 3 :

Si la charge moyenne n'augmente pas beaucoup, cela signifie simplement que vos spécifications matérielles et la nature des tâches à traiter se traduisent par un bon débit global, évitant qu'elles ne s'empilent dans la file d'attente des tâches pendant un certain temps.

S'il y avait un phénomène de contention parce que, par exemple, la complexité moyenne des tâches est trop élevée ou que le temps de traitement moyen des tâches prend trop de cycles CPU, alors oui, la charge moyenne augmenterait.

MISE À JOUR :

Ce n'est peut-être pas clair dans ma réponse d'origine, alors je précise maintenant :

La formule exacte de calcul de la charge moyenne est :loadvg = tasks running + tasks waiting (for cores) + tasks blocked .

Vous pouvez certainement avoir un bon débit et approcher une charge moyenne de 24 mais sans pénalité sur le temps de traitement des tâches. D'autre part, vous pouvez également avoir 2 à 4 tâches périodiques qui ne se terminent pas assez rapidement, vous verrez alors le nombre de tâches en attente (pour les cycles CPU) augmenter et vous finirez par atteindre une charge moyenne élevée. Une autre chose qui peut arriver est que des tâches exécutent des opérations d'E/S synchrones en attente, puis bloquent un cœur, réduisent le débit et augmentent la file d'attente des tâches en attente (dans ce cas, vous pouvez voir le iowait changement de métrique)

Solution 4 :

Bien que la réponse de Matthew Ife ait été très utile et nous ait conduit dans la bonne direction, ce n'était pas exactement la cause du comportement dans notre cas. Dans notre cas, nous avons une application Java multi-thread qui utilise le pool de threads, pourquoi aucun travail n'est fait pour créer les tâches réelles.

Cependant, le travail réel effectué par les threads est de courte durée et comprend des attentes d'E/S ou de synchronisation. Comme Matthew le mentionne dans sa réponse, la charge moyenne est échantillonnée par le système d'exploitation, ainsi des tâches de courte durée peuvent être manquées.

J'ai fait un programme Java qui reproduisait le comportement. La classe Java suivante génère une utilisation CPU de 28 % (650 % empilés) sur l'un de nos serveurs. En faisant cela, la charge moyenne est d'environ 1,3. La clé ici est le sleep() à l'intérieur du thread, sans lui le calcul de charge est correct.

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class MultiThreadLoad {

    private ThreadPoolExecutor e = new ThreadPoolExecutor(200, 200, 0l, TimeUnit.SECONDS,
            new ArrayBlockingQueue<Runnable>(1000), new ThreadPoolExecutor.CallerRunsPolicy());

    public void load() {
        while (true) {
            e.execute(new Runnable() {

                @Override
                public void run() {
                    sleep100Ms();
                    for (long i = 0; i < 5000000l; i++)
                        ;
                }

                private void sleep100Ms() {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            });
        }
    }

    public static void main(String[] args) {
        new MultiThreadLoad().load();
    }

}

Pour résumer, la théorie est que les threads de nos applications sont souvent inactifs et effectuent ensuite un travail de courte durée, raison pour laquelle les tâches ne sont pas correctement échantillonnées par le calcul de la charge moyenne.

Solution 5 :

La charge moyenne inclut les tâches qui sont bloquées sur les E/S du disque, vous pouvez donc facilement avoir une utilisation nulle du processeur et une charge moyenne de 10 simplement en ayant 10 tâches essayant toutes de lire à partir d'un disque très lent. Ainsi, il est courant qu'un serveur occupé commence à écraser le disque et toutes les recherches provoquent de nombreuses tâches bloquées, augmentant la charge moyenne, tandis que l'utilisation du processeur diminue, car toutes les tâches sont bloquées sur le disque.


Linux
  1. Comment vérifier la charge du serveur sur un serveur Windows

  2. Linux - Comment la charge moyenne fonctionne-t-elle avec les processeurs modernes ?

  3. Que signifie la charge moyenne sous Unix/Linux ?

  4. Charge serveur élevée, processeur inactif. NFS la cause ?

  5. Que signifie « agréable » sur les graphiques d'utilisation du processeur ?

Comment créer une charge CPU à 100 % sur un système Linux

Comprendre la charge moyenne dans cPanel.

Utilisation élevée du processeur - Installation de SQL non terminée

Qu'est-ce que la moyenne de charge sous Linux ?

Comment vérifier l'utilisation ou l'utilisation du processeur Linux

Jusqu'où la charge du système peut-elle aller ?