Hohe CPU-Auslastung bei geringer Auslastung


28

Wir stoßen auf ein merkwürdiges Verhalten, bei dem wir eine hohe CPU-Auslastung, aber einen recht niedrigen Lastdurchschnitt feststellen.

Das Verhalten wird am besten durch die folgenden Grafiken unseres Überwachungssystems veranschaulicht.

CPU-Auslastung und Auslastung

Gegen 11:57 Uhr steigt die CPU-Auslastung von 25% auf 75%. Der Lastdurchschnitt wird nicht wesentlich verändert.

Wir betreiben Server mit 12 Cores mit jeweils 2 Hyper-Threads. Das Betriebssystem sieht dies als 24 CPUs.

Die CPU-Auslastungsdaten werden durch Ausführen /usr/bin/mpstat 60 1jeder Minute erfasst . Die Daten für die allZeile und die %usrSpalte werden in der obigen Tabelle angezeigt. Ich bin sicher, dass dies den Durchschnitt pro CPU-Daten zeigt, nicht die "gestapelte" Auslastung. Während wir in der Grafik eine Auslastung von 75% sehen, sehen wir einen Prozess, der zeigt, dass ungefähr 2000% "gestapelte" CPU verwendet werden top.

Der Lastmittelwert wird aus /proc/loadavgjeder Minute ermittelt.

uname -a gibt:

Linux ab04 2.6.32-279.el6.x86_64 #1 SMP Wed Jun 13 18:24:36 EDT 2012 x86_64 x86_64 x86_64 GNU/Linux

Linux dist is Red Hat Enterprise Linux Server release 6.3 (Santiago)

Wir betreiben einige Java-Webanwendungen unter ziemlich hoher Last auf den Maschinen, rechnen mit 100 Anfragen / s pro Maschine.

Wenn ich die CPU-Auslastungsdaten richtig interpretiere, bedeutet dies bei einer CPU-Auslastung von 75%, dass unsere CPUs durchschnittlich 75% der Zeit einen Prozess ausführen. Wenn unsere CPUs jedoch 75% der Zeit ausgelastet sind, sollten wir dann keinen höheren Auslastungsdurchschnitt sehen? Wie können die CPUs zu 75% ausgelastet sein, wenn sich nur 2-4 Jobs in der Ausführungswarteschlange befinden?

Interpretieren wir unsere Daten richtig? Was kann dieses Verhalten verursachen?


Zeigt das Überwachungssystem eine normalisierte CPU-Auslastung (Auslastung / #CPUs) an? Die normale Linux-CPU-Auslastung ist systemübergreifend nur schwer zu vergleichen, da einige Tools stattdessen eine normalisierte CPU-Auslastung verwenden.
Brian,

Meinen Sie damit, jeden Datenpunkt durch die Anzahl der CPUs zu teilen? Dh loadavg / 24 in unserem Fall? Ich kann leicht ein solches Diagramm aus den Daten erstellen, wenn das hilft.
K Erlandsson

Ich schlug vor, dass Ihr Diagramm das bereits zeigt.
Brian,

Ah, tut mir leid, dass ich dich missverstanden habe. Es wäre eine nette Erklärung gewesen, aber leider wird der systemweite Lastdurchschnitt angezeigt. Ich habe es nur dreifach überprüft.
K Erlandsson

Antworten:


51

Zumindest unter Linux sind der Lastdurchschnitt und die CPU-Auslastung zwei verschiedene Faktoren. Der Lastdurchschnitt gibt an, wie viele Tasks über einen bestimmten Zeitraum in einer Kernel-Ausführungswarteschlange warten (nicht nur CPU-Zeit, sondern auch Festplattenaktivität). Die CPU-Auslastung ist ein Maß für die aktuelle Auslastung der CPU. Die höchste Auslastung, die ein einzelner CPU-Thread, der für eine Minute an 100% gebunden war, zum 1-Minuten-Durchschnitt "beitragen" kann, ist 1. Eine 4-Kern-CPU mit Hyperthreading (8 virtuelle Kerne), die für 1 Minute an 100% gebunden war, würde 8 dazu beitragen der 1-Minuten-Lastdurchschnitt.

Oft haben diese beiden Zahlen Muster, die miteinander korrelieren, aber man kann sie nicht als gleich ansehen. Sie können eine hohe Auslastung mit einer CPU-Auslastung von nahezu 0% haben (z. B. wenn viele E / A-Daten im Wartezustand hängen bleiben) und Sie können eine CPU-Auslastung von 1 und 100% haben, wenn ein einzelner Thread-Prozess ausgeführt wird volle Neigung. Auch für kurze Zeit können Sie die CPU bei fast 100% sehen, aber die Last ist immer noch unter 1, weil die durchschnittlichen Metriken noch nicht "aufgeholt" haben.

Ich habe gesehen, dass ein Server eine Auslastung von über 15.000 hat (ja, das ist wirklich kein Tippfehler) und eine CPU von fast 0%. Es geschah, weil eine Samba-Freigabe Probleme hatte und viele, viele Clients in einem E / A-Wartezustand stecken blieben. Wenn Sie regelmäßig eine hohe Auslastung ohne entsprechende CPU-Aktivität feststellen, liegt möglicherweise ein Speicherproblem vor. Auf virtuellen Maschinen kann dies auch bedeuten, dass andere VMs auf demselben VM-Host um Speicherressourcen kämpfen.

Hohe Auslastung ist auch nicht unbedingt eine schlechte Sache. In den meisten Fällen bedeutet dies lediglich, dass das System voll ausgelastet ist oder möglicherweise nicht mehr mithalten kann (wenn die Auslastungszahl höher ist als die Anzahl der Prozessorkerne). An einem Ort, an dem ich ein Systemadministrator war, hatte er jemanden, der die durchschnittliche Auslastung seines Primärsystems genauer beobachtete als Nagios. Wenn die Last hoch war, riefen sie mich 24/7 schneller an, als Sie SMTP sagen könnten. Die meiste Zeit war nichts wirklich falsch, aber sie verbanden die Ladungsnummer mit etwas Falschem und beobachteten es wie ein Falke. Nach der Überprüfung antwortete ich normalerweise, dass das System gerade seinen Job erledigt. Natürlich war dies derselbe Ort, an dem die Last über 15000 anstieg (nicht derselbe Server), und manchmal bedeutet dies, dass etwas nicht stimmt. Sie müssen den Zweck Ihres Systems berücksichtigen. Wenn es sich um ein Arbeitstier handelt, ist mit einer natürlich hohen Belastung zu rechnen.


Wie meinst du damit, dass ich mit einem einzigen Thread-Prozess eine Last von 1 und 100% CPU haben kann? Über was für Threads redest du? Wenn wir unsere Java-Prozesse betrachten, haben sie Unmengen von Threads, aber ich ging davon aus, dass die Threads aus Sicht des Betriebssystems als Prozesse behandelt wurden (sie haben schließlich unter Linux separate PIDs). Könnte es sein, dass ein einzelner Java-Prozess mit mehreren Threads aus Sicht des Lastdurchschnitts nur als eine Aufgabe gezählt wird?
K Erlandsson

Ich habe gerade selbst einen Test durchgeführt. Die Threads in einem Java-Prozess tragen zum Lastdurchschnitt bei, als ob sie separate Prozesse wären. Ich würde mich über eine Klarstellung des oben erwähnten Thread-Prozesses freuen. Vielen Dank!
K Erlandsson

Ich meine, wenn Sie einen Nicht-Multithreading-Prozess haben (dh einen, der jeweils nur eine einzelne CPU verwendet). Wenn Sie beispielsweise nur ein einfaches C-Programm schreiben, das eine Busy-Schleife ausführt, wird nur ein Thread ausgeführt und es wird jeweils nur 1 CPU verwendet.
Dienstag,

Alle Informationen, die ich gefunden habe, besagen, dass Threads vom Kernel aus gesehen und bei der Berechnung der Last als separate Prozesse gelten. Daher verstehe ich nicht, wie ich einen Multi-Thread-Prozess bei voller Neigung ausführen kann, der zu 1 Last und 100% CPU auf einem Multi-CPU-System führt. Könnten Sie mir bitte helfen zu verstehen, wie Sie meinen?
K Erlandsson

Für alle, die mehr Details suchen: "Linux Load Averages: Solving the Mystery" von Brendan Gregg hatte alle Antworten, die ich jemals brauchte.
Nickolay

24

Last ist eine sehr irreführende Zahl. Nimm es mit einem Körnchen Salz.

Wenn Sie viele Aufgaben in sehr schneller Folge erstellen, die sehr schnell abgeschlossen werden, ist die Anzahl der Prozesse in der Ausführungswarteschlange zu gering, um die Last für sie zu registrieren (der Kernel zählt die Last alle fünf Sekunden).

Betrachten Sie dieses Beispiel: Auf meinem Host mit 8 logischen Kernen registriert dieses Python-Skript eine hohe CPU-Auslastung (ca. 85%), jedoch kaum Auslastung.

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()

Eine andere Implementierung vermeidet diese waitin Gruppen von 8 (was den Test verzerren würde). Hier versucht das übergeordnete Element immer, die Anzahl der untergeordneten Elemente auf der Anzahl der aktiven CPUs zu halten, sodass es viel beschäftigter als die erste Methode und hoffentlich genauer ist.

/* 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");
  }
}

Der Grund für dieses Verhalten ist, dass der Algorithmus mehr Zeit für das Erstellen von untergeordneten Prozessen benötigt als für das Ausführen der eigentlichen Aufgabe (bis 10000). Noch nicht erstellte Tasks können nicht in den Status 'ausführbar' gezählt werden, beanspruchen jedoch% sys an CPU-Zeit, da sie erzeugt werden.

Die Antwort könnte also in Ihrem Fall sein, dass bei jeder Arbeit eine große Anzahl von Aufgaben in schneller Folge (Threads oder Prozesse) anfällt.


Vielen Dank für den Vorschlag. Die Tabelle in meiner Frage zeigt% Benutzerzeit (CPU-Systemzeit ist ausgeschlossen, die Systemzeit nimmt nur geringfügig zu). Könnten viele kleine Aufgaben die Erklärung sein? Wenn der Lastdurchschnitt alle 5 Sekunden abgetastet wird, werden die von mpstat angegebenen CPU-Auslastungsdaten häufiger abgetastet?
K Erlandsson

Ich bin nicht vertraut damit, wie die CPU-Abtastung dort durchgeführt wird. Lies niemals die Kernel-Quelle darüber. In meinem Beispiel betrug% usr 70% + und% sys 15%.
Matthew Ife

Gute Beispiele!
Xavier Lucas

5

Wenn sich der Lastdurchschnitt nicht wesentlich erhöht, bedeutet dies lediglich, dass Ihre Hardwarespezifikationen und die Art der zu verarbeitenden Aufgaben einen guten Gesamtdurchsatz ergeben, sodass sie für einige Zeit nicht in der Aufgabenwarteschlange angehäuft werden.

Wenn es ein Konfliktphänomen gibt, weil beispielsweise die durchschnittliche Taskkomplexität zu hoch ist oder die durchschnittliche Taskverarbeitungszeit zu viele CPU-Zyklen in Anspruch nimmt, würde der Lastdurchschnitt steigen.

UPDATE:

In meiner ursprünglichen Antwort ist es möglicherweise nicht klar, daher erkläre ich jetzt:

Die genaue Formel der Lastdurchschnittsberechnung ist: loadvg = tasks running + tasks waiting (for cores) + tasks blocked.

Sie können auf jeden Fall einen guten Durchsatz erzielen und sich einem Lastdurchschnitt von 24 annähern, ohne die Bearbeitungszeit der Aufgaben zu beeinträchtigen. Auf der anderen Seite können auch 2-4 periodische Aufgaben nicht schnell genug erledigt werden, dann wird die Anzahl der wartenden Aufgaben (für CPU-Zyklen) zunehmen und Sie werden schließlich einen hohen Lastdurchschnitt erreichen. Eine andere Möglichkeit besteht darin, dass Aufgaben ausstehende synchrone E / A-Vorgänge ausführen und dann einen Kern blockieren, den Durchsatz verringern und die Warteschlange für wartende Aufgaben vergrößern (in diesem Fall kann sich die iowaitMetrik ändern).


Meines Wissens umfasst der Lastdurchschnitt auch die Aufgaben, die derzeit ausgeführt werden. Das würde bedeuten, dass wir definitiv einen Anstieg des Lastdurchschnitts haben können, ohne dass die CPUs tatsächlich konkurrieren müssen. Oder irre ich mich / missverstehe ich dich?
K Erlandsson

@KristofferE Du hast vollkommen recht. Die aktuelle Formel lautet loadavg = Läuft + Aufgaben warten (auf verfügbare Kerne) + Aufgaben blockiert. Dies bedeutet, dass Sie eine durchschnittliche Auslastung von 24 haben können, keine Aufgabe ansteht oder blockiert ist und somit nur eine "volle Auslastung" oder Ihre Hardwarekapazität ohne Konkurrenz haben können. Da Sie hinsichtlich des Lastdurchschnitts im Verhältnis zur Anzahl der ausgeführten Prozesse im Verhältnis zur CPU-Auslastung verwirrt waren, habe ich mich bei meiner Antwort hauptsächlich auf Erklärungen konzentriert, wie ein Lastdurchschnitt mit insgesamt so wenigen ausgeführten Prozessen noch wachsen kann. Möglicherweise ist es nach dem erneuten Lesen nicht ganz so klar.
Xavier Lucas

2

Der Lastdurchschnitt umfasst Aufgaben, die auf Datenträger-E / A blockiert sind, sodass Sie problemlos eine CPU-Auslastung von Null und einen Lastdurchschnitt von 10 erreichen können, indem Sie 10 Aufgaben ausführen, die alle versuchen, von einem sehr langsamen Datenträger zu lesen. Daher ist es üblich, dass ein ausgelasteter Server die Festplatte auslastet und alle Suchvorgänge viele blockierte Aufgaben verursachen, wodurch die durchschnittliche Auslastung steigt, während die CPU-Auslastung sinkt, da alle Aufgaben auf der Festplatte blockiert sind.


1

Die Antwort von Matthew Ife war zwar sehr hilfreich und führte uns in die richtige Richtung, aber es war nicht genau das, was das Verhalten in unserem Fall verursachte. In unserem Fall haben wir eine Java-Anwendung mit mehreren Threads, die Thread-Pooling verwendet, weshalb beim Erstellen der eigentlichen Aufgaben keine Arbeit geleistet wird.

Die eigentliche Arbeit der Threads ist jedoch kurzlebig und umfasst E / A-Wartezeiten oder Synchronisierungswartezeiten. Wie Matthew in seiner Antwort erwähnt, wird der Lastdurchschnitt vom Betriebssystem abgetastet, sodass kurzlebige Aufgaben übersehen werden können.

Ich habe ein Java-Programm erstellt, das das Verhalten reproduziert. Die folgende Java-Klasse generiert auf einem unserer Server eine CPU-Auslastung von 28% (650% gestapelt). Dabei liegt der Lastdurchschnitt bei ca. 1,3. Der Schlüssel hier ist der sleep () innerhalb des Threads, ohne ihn ist die Lastberechnung korrekt.

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();
    }

}

Zusammenfassend lässt sich sagen, dass die Threads in unseren Anwendungen häufig inaktiv sind und dann eine kurzlebige Arbeit verrichten, weshalb die Aufgaben bei der Berechnung des Lastdurchschnitts nicht korrekt erfasst werden.


0

Lastdurchschnitt ist die durchschnittliche Anzahl von Prozessen in der CPU-Warteschlange. Es ist systemspezifisch. Sie können nicht sagen, dass ein LA auf allen Systemen generisch hoch und ein anderer niedrig ist. Sie haben also 12 Kerne, und um LA signifikant zu steigern, muss die Anzahl der Prozesse wirklich hoch sein.

Eine andere Frage ist, was mit dem Diagramm "CPU-Auslastung" gemeint ist. Wenn es aus SNMP stammt, wie es sein sollte und Ihre SNMP-Implementierung es ist net-snmp, dann stapelt es die CPU-Last von jeder Ihrer 12 CPUs. Also für net-snmpdie Gesamtmenge der CPU - Auslastung beträgt 1200%.

Wenn meine Annahmen stimmen, hat sich die CPU-Auslastung nicht wesentlich erhöht. Somit hat LA nicht signifikant zugenommen.


Die CPU-Auslastung wird von mpstat, der allZeile, übernommen. Ich bin ziemlich sicher, dass es ein Durchschnitt über alle CPUs ist, es ist nicht gestapelt. Wenn das Problem auftritt, zeigt oben beispielsweise die CPU-Auslastung von 2000% für einen Prozess. Das ist Stapelverwendung.
K Erlandsson

0

Das Szenario hier ist nicht besonders unerwartet, obwohl es ein wenig ungewöhnlich ist. Was Xavier anspricht, aber nicht viel entwickelt, ist, dass Linux (standardmäßig) und die meisten Unix-Varianten auf einem fehlerfreien Computer präventives Multitasking implementieren, Aufgaben jedoch selten vorbelegt werden. Jeder Task ist eine Zeitscheibe für die Belegung der CPU zugeordnet. Sie wird nur dann vorbelegt, wenn diese Zeit überschritten wird und andere Tasks ausgeführt werden müssen (beachten Sie, dass beim Laden die durchschnittliche Anzahl der Prozesse in der CPU sowie die Anzahl der ausgeführten Prozesse angegeben wird). . In den meisten Fällen wird ein Prozess nicht unterbrochen, sondern erbracht.

(Im Allgemeinen müssen Sie sich nur Gedanken über die Auslastung machen, wenn die Anzahl der CPUs knapp wird - dh wenn der Scheduler mit dem Vorauslesen von Aufgaben beginnt.)

Wenn unsere CPUs 75% der Zeit ausgelastet sind, sollten wir dann keinen höheren Auslastungsdurchschnitt sehen?

Es dreht sich alles um das Aktivitätsmuster, die deutlich erhöhte Auslastung der CPU durch einige Tasks (höchstwahrscheinlich eine kleine Minderheit) wirkte sich nicht negativ auf die Verarbeitung anderer Tasks aus. Wenn Sie die verarbeiteten Transaktionen isolieren könnten, würde sich während der Verlangsamung vermutlich eine neue Gruppe bilden, während die vorhandene Aufgabengruppe nicht betroffen war.

aktualisieren

Ein häufiges Szenario, in dem eine hohe CPU-Auslastung ohne großen Anstieg der Auslastung auftreten kann, besteht darin, dass eine Aufgabe eine (oder eine Sequenz) anderer Aufgaben auslöst, z. B. beim Empfang einer Netzwerkanforderung, leitet der Handler die Anforderung an einen separaten Thread, den separaten Thread Dann werden einige asynchrone Aufrufe an andere Prozesse gesendet. Durch das Abtasten der Runqueue wird die Last als niedriger gemeldet, als sie tatsächlich ist. Sie steigt jedoch nicht linear mit der CPU-Auslastung an. Die ausgelöste Taskkette wäre ohne die nicht ausführbar gewesen Anfangsereignis und weil sie (mehr oder weniger) sequentiell auftreten, wird die Ausführungswarteschlange nicht aufgeblasen.


Das OP lieferte ursprünglich Hinweise darauf, dass die Gesamt-CPU% "2000%" war, was darauf hindeutet, dass viele Aufgaben die CPU beanspruchen, und nicht nur 1 ausgelasteter Prozess. Wenn es für eine Minute konstante 2000% wären, würden Sie normalerweise davon ausgehen, dass die Last 20-ish ist.
Matthew Ife

... in einem Kommentar, nicht in der Frage, und da ist er sich nicht ganz sicher. Wenn die Option 'ALL' fehlt, gibt mpstat den Gesamtverbrauch in% und nicht den Durchschnitt an. Das ändert aber nichts an der Antwort - es geht um das Aktivitätsmuster.
Symcbean

Ich bin zu 100% davon überzeugt, dass die CPU-Auslastung, die wir in der Tabelle sehen, der "Durchschnitt pro CPU" ist. Mpstat wird ohne ALL ausgeführt, wobei jedoch nur die Informationen pro CPU weggelassen werden. In der allZeile wird weiterhin der Durchschnitt pro CPU angezeigt . Ich werde die Frage klären.
K Erlandsson

Könnten Sie bitte den letzten Abschnitt etwas näher erläutern? Ich verstehe nicht, was Sie meinen, während der Teil meiner Frage, den Sie zitiert haben, der Teil ist, den ich am schwersten verstehe.
K Erlandsson
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.