Frage Hohe CPU-Auslastung, aber niedriger Lastdurchschnitt


Wir geraten in ein merkwürdiges Verhalten, in dem wir eine hohe CPU-Auslastung, aber einen relativ niedrigen Lastdurchschnitt sehen.

Das Verhalten wird am besten anhand der folgenden Diagramme aus unserem Überwachungssystem veranschaulicht.

CPU usage and load

Um 11:57 Uhr steigt die CPU-Auslastung von 25% auf 75%. Der Lastdurchschnitt wird nicht signifikant geändert.

Wir betreiben Server mit 12 Kernen mit je 2 Hyper-Threads. Das OS sieht dies als 24 CPUs.

Die CPU-Nutzungsdaten werden durch Ausführen gesammelt /usr/bin/mpstat 60 1 jede Minute. Die Daten für die all Reihe und die %usr Spalte wird in der obigen Tabelle angezeigt. Ich bin sicher, dies zeigt den Durchschnitt pro CPU-Daten, nicht die "gestapelte" Nutzung. Während wir eine Auslastung von 75% im Diagramm sehen, sehen wir einen Prozess, der zeigt, dass etwa 2000% "gestapelte" CPUs in top.

Die Lastdurchschnittszahl wird aus genommen /proc/loadavg jede Minute.

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 ist Dist Red Hat Enterprise Linux Server release 6.3 (Santiago)

Wir betreiben ein paar Java-Webanwendungen unter ziemlich starker Auslastung der Maschinen, denken an 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 zu 75% ausgelastet sind, sollten wir dann nicht einen höheren durchschnittlichen Lastwert sehen? Wie können die CPUs zu 75% ausgelastet sein, während wir nur 2-4 Jobs in der Run Queue haben?

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


19
2018-02-12 11:53


Ursprung


Zeigt das Überwachungssystem eine normalisierte CPU-Auslastung (Last / #CPUs) an? Regelmäßige Linux-CPU-Last ist schwer über Systeme mit unterschiedlichen Core / CPU-Werten zu vergleichen, daher verwenden einige Tools eine normalisierte CPU-Last. - Brian
Meinst du, jeden Datenpunkt mit der Anzahl der CPUs zu teilen? I.e. loadavg / 24 in unserem Fall? Ich kann einfach ein solches Diagramm aus den Daten erstellen, wenn das hilft. - K Erlandsson
Sch sch sch sch sch sch sch sch sch sch sch sch sch sch sch sch 100 sch 100 sch sch sch sch sch sch sch sch sch dieser sch sch sch sch sch sch sch sch sch sch sch sch sch 100 100 dieser sch sch 100 100 sch sch dieser - Brian
Ah, tut mir leid, dass ich dich missverstanden habe. Es wäre eine schöne Erklärung gewesen, aber leider wird der systemweite Lastdurchschnitt angezeigt. Ich habe es nur dreifach überprüft. - K Erlandsson


Antworten:


Unter Linux sind der Lastdurchschnitt und die CPU-Auslastung eigentlich zwei verschiedene Dinge. Der Lastdurchschnitt ist ein Maß dafür, wie viele Aufgaben in einer Kernel-Ausführungswarteschlange (nicht nur CPU-Zeit, sondern auch Festplattenaktivität) über einen bestimmten Zeitraum warten. Die CPU-Auslastung ist ein Maß dafür, wie ausgelastet die CPU gerade ist. Die meiste Last, die ein einzelner CPU-Thread bei 100% für eine Minute hat, kann zum 1-Minuten-Lastdurchschnitt "1" beitragen. Eine 4-Kern-CPU mit Hyperthreading (8 virtuelle Kerne) alle bei 100% für 1 Minute würde 8 zu beitragen der 1-Minuten-Lastdurchschnitt.

Oftmals haben diese zwei Zahlen Muster, die miteinander korrelieren, aber Sie können sie nicht als die gleichen betrachten. Sie können eine hohe Auslastung mit fast 0% CPU-Auslastung haben (z. B. wenn eine große Anzahl von IO-Daten in einem Wartezustand hängen geblieben ist) und Sie eine Auslastung von 1 und 100% CPU haben, wenn ein Einzelprozess ausgeführt wird volle Neigung. Auch für kurze Zeit sehen Sie die CPU bei fast 100%, aber die Last ist immer noch unter 1, weil die durchschnittlichen Metriken noch nicht "aufgeholt" haben.

Ich habe gesehen, dass ein Server eine Last von über 15.000 hat (ja, das ist kein Tippfehler) und eine CPU% von fast 0%. Es passierte, weil eine Samba-Freigabe Probleme hatte und viele und viele Clients in einem IO-Wartezustand stecken blieben. Wenn Sie eine reguläre hohe Ladezahl ohne entsprechende CPU-Aktivität sehen, haben Sie wahrscheinlich ein Speicherproblem. Auf virtuellen Maschinen kann dies auch bedeuten, dass andere VMs stark um Speicherressourcen auf demselben VM-Host konkurrieren.


30
2018-02-12 21:38



Wie meinst du, dass ich eine Last von 1 und 100% CPU mit einem Single-Thread-Prozess haben kann? Über welche Art von Threads redest du? Wenn wir unsere Java-Prozesse betrachten, haben sie Tonnen von Threads, aber ich ging davon aus, dass die Threads als Prozesse aus der Perspektive des Betriebssystems behandelt wurden (sie haben schließlich separate PIDs unter Linux). Könnte es sein, dass ein einzelner Java-Prozess mit mehreren Threads nur als eine Aufgabe aus einer durchschnittlichen Lastperspektive gezählt wird? - K Erlandsson
Ich habe gerade selbst einen Test gemacht, die Threads in einem Java-Prozess tragen zum Lastdurchschnitt bei, als ob sie separate Prozesse wären (zB eine Java-Klasse, die 10 Threads in einer Busy-Wait-Schleife ausführt, was eine Last nahe 10 ergibt). Ich würde mich über den oben erwähnten Gewindeprozess freuen. Vielen Dank! - K Erlandsson
Ich meine, wenn Sie einen Nicht-Multithreading-Prozess haben (dh einen, der nur eine einzelne CPU gleichzeitig verwendet). Wenn Sie beispielsweise ein einfaches C-Programm schreiben, das eine Busy-Schleife ausführt, wird nur ein einzelner Thread ausgeführt, und es wird jeweils nur 1 CPU verwendet. - deltaray
Alle Informationen, die ich gefunden habe, besagt, dass Threads als separate Prozesse gezählt werden, wenn sie vom Kernel aus betrachtet werden und wenn die Last berechnet wird. Daher sehe ich nicht, wie ich einen Multithread-Prozess bei voller Neigung haben könnte, was zu einer Last und 100% CPU auf einem Multi-CPU-System führt. 100 100 100 100 100 sch 100 sch 100 dieser dieser dieser dieser dieser sch sch sch sch sch sch dieser sch sch sch 100 dieser sch sch sch dieser sch dieser sch dieser 100 sch sch sch sch sch sch sch sch sch sch sch sch sch sch sch sch dieser - K Erlandsson
Für alle, die mehr Details suchen: "Linux Load Averages: Das Geheimnis lüften" von Brendan Gregg hatte alle Antworten, die ich jemals brauchte. - Nickolay


Die Ladung ist eine sehr betrügerische 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 klein, um die Last für sie zu registrieren (der Kernel zählt die Last einmal alle fünf Sekunden).

Betrachten Sie dieses Beispiel, auf meinem Host, der über 8 logische Kerne verfügt, registriert dieses Python-Skript eine hohe CPU-Auslastung im oberen Bereich (etwa 85%), jedoch kaum eine Last.

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, diese vermeidet wait in Gruppen von 8 (was den Test verfälschen würde). Hier versucht das Elternteil immer, die Anzahl der Kinder auf der Anzahl der aktiven CPUs zu belassen, so dass es viel beschäftigter sein wird als die erste Methode und hoffentlich genauer.

/* 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 liegt darin, dass der Algorithmus mehr Zeit zum Erstellen von untergeordneten Prozessen benötigt als zum Ausführen der eigentlichen Aufgabe (bis 10000). Aufgaben, die noch nicht erstellt wurden, können nicht in den Status 'runnable' gezählt werden, nehmen jedoch% sys CPU-Zeit in Anspruch, wenn sie erstellt werden.

Die Antwort könnte also wirklich in Ihrem Fall liegen, dass jede Arbeit, die gerade ausgeführt wird, eine große Anzahl von Aufgaben in schneller Folge hervorbringt (Threads oder Prozesse).


20
2018-02-12 13:05



Danke für den Vorschlag. Das Diagramm in meiner Frage zeigt% Benutzerzeit (CPU-Systemzeit ist ausgeschlossen, wir sehen nur eine sehr geringe Erhöhung der Systemzeit). Könnten viele kleine Aufgaben die Erklärung sein? Wenn der Lastdurchschnitt alle 5 Sekunden abgetastet wird, werden die CPU-Nutzungsdaten, die von mpstat angegeben werden, häufiger abgetastet? - K Erlandsson
100 100 sch 100 sch 100 sch 100 sch 100 sch 100 sch 100 sch 100 sch 100 sch 100 sch 100 sch 100 sch 100 sch 100 sch 100 sch 100 100 100 100 100 sch 100 sch sch 100 sch 100 sch 100 sch 100 sch 100 sch 100 dieser Lesen Sie niemals die Kernel-Quelle dazu. In meinem Beispiel war% usr 70% + und% sys war 15%. - Matthew Ife
Gute Beispiele! - Xavier Lucas


Wenn der Lastdurchschnitt nicht stark ansteigt, bedeutet dies nur, dass Ihre Hardwarespezifikationen und die Art der zu verarbeitenden Aufgaben zu einem guten Gesamtdurchsatz führen, sodass sie nicht für eine gewisse Zeit in der Aufgabenwarteschlange aufgestapelt werden.

Wenn es ein Konkurrenzphänomen gab, weil zum Beispiel die durchschnittliche Aufgabenkomplexität zu hoch ist oder die durchschnittliche Verarbeitungszeit der Aufgabe zu viele CPU-Zyklen benötigt, dann würde ja der Lastdurchschnitt zunehmen.

UPDATE:

Es ist vielleicht nicht klar in meiner ursprünglichen Antwort, also klär ich jetzt:

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

Sie können definitiv einen guten Durchsatz haben und einem Lastdurchschnitt von 24 nahe kommen, aber ohne Zeitaufwand für die Verarbeitung der Aufgaben. Auf der anderen Seite können Sie auch 2-4 periodische Aufgaben haben, die nicht schnell genug abgeschlossen werden, dann wird die Anzahl der wartenden Aufgaben (für CPU-Zyklen) wachsen und Sie werden schließlich einen hohen Lastdurchschnitt erreichen. Eine andere Sache, die passieren kann, sind Aufgaben, die ausstehende synchrone E / A-Operationen ausführen, dann einen Kern blockieren, den Durchsatz verringern und die Warteschlange für wartende Aufgaben wachsen lassen (in diesem Fall sehen Sie möglicherweise die iowait metrische Änderung)


5
2018-02-12 13:00



Es versteht sich, dass der Lastdurchschnitt auch die aktuell ausgeführten Aufgaben umfasst. Das würde bedeuten, dass wir definitiv einen Anstieg des Lastdurchschnitts ohne tatsächliche Konkurrenz für die CPUs haben können. Oder irre ich mich / missverstehe dich? - K Erlandsson
100 sch 100 sch 100 100 100 100 100 100 100 sch 100 sch 100 sch 100 sch 100 sch 100 sch 100 sch 100 100 100 100 100 100 100 sch 100 sch 100 100 100 100 100 100 sch 100 sch 100 100 100 100 100 100 sch 100 dieser Die tatsächliche Formel ist loadavg = taks running + Aufgaben warten (für verfügbare Kerne) + Aufgaben blockiert. Dies bedeutet, dass Sie einen Lastdurchschnitt von 24 haben können, keine Aufgabe warten oder blockiert werden und somit nur eine "vollständige Nutzung" oder Ihre Hardwarekapazität ohne jegliche Konkurrenz haben. Da Sie sich über den Lastdurchschnitt im Vergleich zur Anzahl der ausgeführten Prozesse im Vergleich zur CPU-Auslastung nicht sicher waren, konzentrierte ich meine Antwort hauptsächlich auf Erklärungen darüber, wie der Lastdurchschnitt mit nur wenigen laufenden Prozessen insgesamt noch wachsen kann. Es ist vielleicht nicht so klar, nachdem es neu gelesen wurde. - Xavier Lucas


Der Lastdurchschnitt enthält Tasks, die auf der Festplatten-IO blockiert sind, sodass Sie leicht eine CPU-Auslastung von 10 und einen Lastdurchschnitt von 10 erreichen können, wenn 10 Tasks alle versuchen, von einer sehr langsamen Festplatte zu lesen. Daher ist es üblich, dass ein ausgelasteter Server mit dem Überspielen der Festplatte beginnt und alle Suchvorgänge viele blockierte Aufgaben verursachen, was den Lastdurchschnitt erhöht, während die CPU-Nutzung sinkt, da alle Aufgaben auf der Festplatte blockiert sind.


2
2018-02-12 20:34





Während die Antwort von Matthew Ife sehr hilfreich war und uns in die richtige Richtung führte, war es nicht genau das, was das Verhalten in unserem Fall verursachte. In unserem Fall haben wir eine Multi-Thread-Java-Anwendung, die Thread-Pooling verwendet, warum keine Arbeit getan wird, um die eigentlichen Aufgaben zu erstellen.

Die tatsächliche Arbeit der Threads ist jedoch kurzlebig und umfasst E / A-Wartezeiten oder Synchronisationswartezeiten. Wie Matthew in seiner Antwort erwähnt, wird der Lastdurchschnitt vom OS abgetastet, so dass kurzlebige Aufgaben verpasst werden können.

Ich habe ein Java-Programm erstellt, das das Verhalten reproduziert. Die folgende Java-Klasse generiert eine CPU-Auslastung von 28% (650% gestapelt) auf einem unserer Server. Der Lastdurchschnitt beträgt dabei etwa 1,3. Der Schlüssel hier ist der Schlaf () innerhalb des Threads, ohne dass die Lastberechnung korrekt ist.

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 ist die Theorie, dass die Threads in unseren Anwendungen häufig ungenutzt sind und dann kurzlebige Arbeit ausführen, weshalb die Tasks von der Lastdurchschnittsberechnung nicht korrekt abgetastet werden.


1
2018-02-17 08:45





Lastdurchschnitt ist die durchschnittliche Anzahl von Prozessen in der CPU-Warteschlange. Es ist spezifisch für jedes System, man kann nicht sagen, dass ein LA generisch auf allen Systemen hoch ist und ein anderes niedrig ist. Sie haben also 12 Kerne, und damit LA deutlich steigt, muss die Anzahl der Prozesse sehr hoch sein.

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

Wenn meine Annahmen richtig sind, hat sich die CPU-Auslastung nicht wesentlich erhöht. Somit stieg LA nicht signifikant.


0
2018-02-12 12:21



Die CPU - Nutzung stammt von mpstat, der all Reihe. Ich bin ziemlich sicher, es ist ein Durchschnitt über alle CPUs, es ist nicht gestapelt. Wenn das Problem auftritt, zeigt top beispielsweise 2000% CPU-Auslastung für einen Prozess. Das ist eine gestapelte Nutzung. - K Erlandsson


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 präemptives Multitasking implementieren, während auf einem gesunden Rechner Aufgaben selten vorweggenommen werden. Jedem Task wird ein Zeitabschnitt für die Belegung der CPU zugewiesen, er wird nur vorbesetzt, wenn er diese Zeit überschreitet und andere Tasks darauf warten, ausgeführt zu werden (beachten Sie, dass load die durchschnittliche Anzahl der Prozesse sowohl in der CPU meldet als auch auf die Ausführung wartet). . Die meiste Zeit wird ein Prozess eher nachgeben als unterbrochen werden.

(Im Allgemeinen müssen Sie sich nur um die Last kümmern, wenn die Anzahl der CPUs knapp wird - d. h. wenn der Scheduler Aufgaben vorwegnimmt.

Wenn unsere CPUs in 75% der Fälle beschäftigt sind, sollten wir nicht einen höheren durchschnittlichen Lastwert sehen?

Es geht um das Aktivitätsmuster, die deutlich erhöhte Auslastung der CPU durch einige Aufgaben (höchstwahrscheinlich eine geringe Prägbarkeit) hat die Bearbeitung anderer Aufgaben nicht beeinträchtigt. Wenn Sie die Transaktionen, die verarbeitet werden, isolieren können, würde ich erwarten, dass Sie während der Verlangsamung eine neue Gruppe auftauchen sehen würden, während die bestehende Aufgabe nicht betroffen war.

aktualisieren

Ein häufiges Szenario, in dem eine hohe CPU ohne einen großen Anstieg der Last auftreten kann, ist, wenn eine Task eine (oder eine Sequenz) anderer Tasks auslöst, z. Beim Empfang einer Netzwerkanforderung leitet der Handler die Anforderung an einen separaten Thread weiter, der seperate Thread führt dann einige asynchrone Aufrufe an andere Prozesse durch. Das Abtasten der Runqueue führt dazu, dass die Last niedriger berichtet wird als sie tatsächlich ist - aber sie steigt nicht linear mit der CPU-Nutzung an - die Kette von Tasks, die ausgelöst wurden, wäre ohne das anfängliche Ereignis nicht ausführbar gewesen, und weil sie (mehr oder weniger) sequentiell auftreten, wird die Run-Warteschlange nicht aufgebläht.


0
2018-02-12 13:55



Das OP lieferte ursprünglich Hinweise, dass die Gesamt-CPU% "2000%" war, was darauf hindeutet, dass es viele Aufgaben gibt, die CPU verbrauchen, und nicht nur einen ausgelasteten Prozess. Wenn es eine konsistente 2000% für eine Minute war, würden Sie normalerweise erwarten, dass die Last 20-ish ist. - Matthew Ife
... in einem Kommentar, nicht in der Frage, und er ist sich nicht sicher. Wenn die Option 'ALL' fehlt, meldet mpstat die Gesamtnutzung% und nicht den Durchschnitt. Aber das ändert nichts an der Antwort - es geht um das Aktivitätsmuster. - symcbean
Ich bin 100% positiv, dass das CPU-Utility, das wir in der Grafik sehen, der "Durchschnitt pro CPU" ist. Mpstat wird ohne ALL ausgeführt, aber das lässt nur die pro-CPU-Informationen, die all Zeile zeigt immer noch den Durchschnitt pro CPU. Ich werde die Frage klären. - K Erlandsson
Könntest du bitte deinen letzten Abschnitt ein wenig ausarbeiten? Ich verstehe nicht, was Sie meinen, während der Teil meiner Frage, den Sie zitiert haben, der Teil ist, den ich am schwierigsten zu verstehen habe. - K Erlandsson