Wysokie wykorzystanie procesora, ale niskie średnie obciążenie

28

Występuje dziwne zachowanie, w którym widzimy wysokie wykorzystanie procesora, ale dość niskie średnie obciążenie.

Zachowanie najlepiej ilustrują następujące wykresy z naszego systemu monitorowania.

Wykorzystanie i obciążenie procesora

Około 11:57 wykorzystanie procesora wzrasta z 25% do 75%. Średnia obciążenia nie ulega znaczącej zmianie.

Obsługujemy serwery z 12 rdzeniami z 2 hiperwątkami każdy. System operacyjny postrzega to jako 24 procesory.

Dane o wykorzystaniu procesora są gromadzone przez uruchamianie /usr/bin/mpstat 60 1każdej minuty. Dane dla allwiersza i %usrkolumny pokazano na powyższym wykresie. Jestem pewien, że to pokazuje średnią na dane procesora, a nie wykorzystanie w stosie. Podczas gdy widzimy 75% wykorzystania na wykresie, widzimy proces pokazujący użycie około 2000% „skumulowanego” procesora top.

Średnia wartość obciążenia jest pobierana z /proc/loadavgkażdej minuty.

uname -a daje:

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

Pracujemy na kilku aplikacjach internetowych Java pod dość dużym obciążeniem na komputerach, pomyślmy 100 żądań / s na maszynę.

Jeśli poprawnie interpretuję dane o wykorzystaniu procesora, gdy mamy 75% wykorzystania procesora, oznacza to, że nasze procesory wykonują proces średnio w 75% przypadków. Jeśli jednak nasze procesory są zajęte w 75% przypadków, czy nie powinniśmy widzieć wyższej średniej obciążenia? Jak procesory mogą być zajęte w 75%, podczas gdy mamy tylko 2-4 zadania w kolejce uruchomień?

Czy interpretujemy nasze dane poprawnie? Co może powodować takie zachowanie?

K Erlandsson
źródło
Czy system monitorowania pokazuje znormalizowane obciążenie procesora (obciążenie / liczba procesorów)? Regularne obciążenie procesora w systemie Linux jest trudne do porównania w systemach z różnymi liczbami rdzeni / procesorów, dlatego niektóre narzędzia używają zamiast tego znormalizowanego obciążenia procesora.
Brian
Czy masz na myśli podzielenie każdego punktu danych przez liczbę procesorów? Czyli loadavg / 24 w naszym przypadku? Mogę łatwo utworzyć taki wykres z danych, jeśli to pomoże.
K Erlandsson,
Sugerowałem, że twój wykres może już to pokazywać.
Brian
Ach, przepraszam za nieporozumienie. Byłoby to miłe wytłumaczenie, ale niestety pokazana jest średnia obciążeń dla całego systemu. Właśnie potroiłem.
K Erlandsson,

Odpowiedzi:

51

Przynajmniej w systemie Linux średnie obciążenie i wykorzystanie procesora to dwie różne rzeczy. Średnia wartość obciążenia jest miarą liczby zadań oczekujących w kolejce uruchomieniowej jądra (nie tylko czas procesora, ale także aktywność dysku) w danym okresie czasu. Wykorzystanie procesora jest miarą tego, jak bardzo procesor jest obecnie zajęty. Największe obciążenie, które pojedynczy wątek procesora ustalony na 100% przez jedną minutę może „przyczynić się” do średniej 1-minutowego obciążenia, wynosi 1. 4-rdzeniowy procesor z hiperwątkiem (8 rdzeni wirtualnych) przy 100% przez 1 minutę przyczyniłby się do 8 średnia wartość obciążenia 1 minuty.

Często te dwie liczby mają wzorce, które korelują ze sobą, ale nie można ich traktować tak samo. Możesz mieć duże obciążenie przy prawie 0% wykorzystaniu procesora (na przykład, gdy wiele danych we / wy utknęło w stanie oczekiwania) i możesz mieć obciążenie 1 i 100% procesora, gdy uruchomiony jest proces jednowątkowy pełne przechylenie. Również przez krótki czas widać procesor na poziomie zbliżonym do 100%, ale obciążenie jest nadal poniżej 1, ponieważ średnie wskaźniki jeszcze nie „nadrobiły”.

Widziałem, że serwer ma obciążenie ponad 15 000 (tak naprawdę to nie jest literówka) i procesor% zbliżony do 0%. Stało się tak, ponieważ w akcji Samby występowały problemy, a wielu klientów utknęło w stanie oczekiwania na zamówienie. Są szanse, że jeśli widzisz regularne wysokie obciążenie bez odpowiadającej mu aktywności procesora, masz jakiś problem z pamięcią. Na maszynach wirtualnych może to również oznaczać, że istnieją inne maszyny wirtualne mocno konkurujące o zasoby pamięci masowej na tym samym hoście maszyny wirtualnej.

Wysokie obciążenie niekoniecznie jest złą rzeczą, przez większość czasu oznacza to, że system jest wykorzystywany do pełnej wydajności, a może nawet nie jest w stanie nadążyć (jeśli liczba obciążenia jest większa niż liczba rdzeni procesora). W miejscu, w którym kiedyś byłem sysadminem, mieli kogoś, kto obserwował średnią obciążenie swojego systemu głównego bliżej niż Nagios. Gdy obciążenie było wysokie, dzwonili do mnie 24/7 szybciej niż można powiedzieć SMTP. Przez większość czasu tak naprawdę nie było nic złego, ale powiązali numer obciążenia z czymś złym i obserwowali go jak jastrząb. Po sprawdzeniu moja odpowiedź była zwykle taka, że ​​system po prostu wykonuje swoją pracę. Oczywiście było to to samo miejsce, w którym obciążenie wzrosło o ponad 15000 (choć nie ten sam serwer), więc czasami oznacza to, że coś jest nie tak. Musisz wziąć pod uwagę cel twojego systemu. Jeśli jest to koń pociągowy, spodziewaj się, że obciążenie będzie naturalnie wysokie.

deltaray
źródło
Co masz na myśli, że mogę mieć obciążenie 1 i 100% procesora za pomocą jednego procesu wątkowego? O jakich wątkach mówisz? Jeśli weźmiemy pod uwagę nasze procesy Java, mają one mnóstwo wątków, ale założyłem, że wątki zostały potraktowane jako procesy z perspektywy systemu operacyjnego (w końcu mają oddzielne PID w Linuksie). Czy może być tak, że pojedynczy wielowątkowy proces Java jest liczony tylko jako jedno zadanie z perspektywy średniej obciążenia?
K Erlandsson,
Właśnie zrobiłem test na własną rękę, wątki w procesie Java przyczyniają się do średniej obciążenia, tak jakby były oddzielnymi procesami (tj. Klasa Java, która uruchamia 10 wątków w pętli zajętego oczekiwania, daje mi obciążenie bliskie 10). Byłbym wdzięczny za wyjaśnienie na temat wątkowego procesu wspomnianego powyżej. Dziękuję Ci!
K Erlandsson,
Mam na myśli, jeśli masz proces nie wielowątkowy (tj. Taki, który korzysta tylko z jednego procesora na raz). Na przykład, jeśli napiszesz prosty program C, który uruchamia zajętą ​​pętlę, działa tylko jeden wątek i używa tylko 1 procesora na raz.
deltaray
Wszystkie informacje, które znalazłem, mówią, że wątki liczą się jako osobne procesy, gdy są widziane z jądra i podczas obliczania obciążenia. Dlatego nie widzę, jak mogę mieć proces wielowątkowy przy pełnym przechyleniu, co powoduje 1 obciążenie i 100% procesora w systemie wieloprocesorowym. Czy możesz mi pomóc zrozumieć, co masz na myśli?
K Erlandsson
Dla każdego, kto szuka bardziej szczegółowych informacji: „Średnie obciążenia systemu Linux: rozwiązywanie tajemnicy” Brendana Gregga miał wszystkie odpowiedzi, których potrzebowałem.
Nickolay
24

Obciążenie to bardzo zwodnicza liczba. Dodaj szczyptę soli.

Jeśli odradzasz wiele zadań w bardzo szybkich odstępach czasu, które kończą się bardzo szybko, liczba procesów w kolejce uruchomień jest zbyt mała, aby zarejestrować dla nich obciążenie (jądro zlicza obciążenie raz na pięć sekund).

Rozważmy ten przykład, na moim hoście, który ma 8 rdzeni logicznych, ten skrypt Pythona zarejestruje duże użycie procesora u góry (około 85%), ale prawie żadne obciążenie.

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

Kolejna implementacja, której unika się waitw grupach po 8 osób (co wypaczyłoby test). W tym przypadku rodzic zawsze stara się utrzymać liczbę dzieci na liczbie aktywnych procesorów, tak aby był on znacznie bardziej zajęty niż pierwsza metoda i, miejmy nadzieję, bardziej dokładny.

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

Przyczyną takiego zachowania jest to, że algorytm spędza więcej czasu na tworzeniu procesów potomnych niż na wykonywaniu rzeczywistego zadania (licząc do 10000). Zadania, które nie zostały jeszcze utworzone, nie mogą się liczyć do stanu „uruchomialnego”, ale zajmą% sys czasu procesora podczas ich odradzania.

Tak więc odpowiedź może naprawdę brzmieć w twoim przypadku, że niezależnie od wykonywanej pracy powstaje duża liczba zadań w krótkim czasie (wątki lub procesy).

Matthew Ife
źródło
Dziękuję za sugestię. Wykres w moim pytaniu pokazuje% czasu użytkownika (czas systemowy procesora jest wykluczony, widzimy tylko niewielki wzrost czasu systemowego). Czy mimo to wiele małych zadań może być wyjaśnieniem? Jeśli próbkowanie średniej obciążenia odbywa się co 5 sekund, czy dane o wykorzystaniu procesora podane przez mpstat są częściej próbkowane?
K Erlandsson,
Nie wiem, jak tam odbywa się próbkowanie procesora. Nigdy nie czytaj o tym źródła jądra. W moim przykładzie% usr wynosiło 70% +, a% sys 15%.
Matthew Ife,
Dobre przykłady!
Xavier Lucas,
5

Jeśli średnia wartość obciążenia nie wzrośnie znacznie, oznacza to po prostu, że specyfikacje sprzętu i charakter zadań do przetworzenia zapewniają dobrą ogólną przepustowość, unikając ich gromadzenia się w kolejce zadań przez pewien czas.

Gdyby wystąpił fenomen rywalizacji, ponieważ na przykład średnia złożoność zadania jest zbyt wysoka lub średni czas przetwarzania zadania zajmuje zbyt wiele cykli procesora, wówczas tak, średnia obciążenie wzrosłaby.

AKTUALIZACJA :

W mojej pierwotnej odpowiedzi może to nie być jasne, więc wyjaśniam teraz:

Dokładna formuła obciążenia średniego obliczeniowy: loadvg = tasks running + tasks waiting (for cores) + tasks blocked.

Zdecydowanie możesz mieć dobrą przepustowość i zbliżyć się do średniej obciążenia wynoszącej 24, ale bez kary za czas przetwarzania zadań. Z drugiej strony możesz również wykonywać 2-4 okresowe zadania, które nie są wykonywane wystarczająco szybko, wtedy zobaczysz rosnącą liczbę zadań oczekujących (na cykle procesora) i ostatecznie osiągniesz wysoką średnią obciążenia. Inną rzeczą, która może się zdarzyć, jest uruchamianie zadań z wybitnymi synchronicznymi operacjami we / wy, a następnie blokowanie rdzenia, obniżenie przepustowości i zwiększenie kolejki zadań oczekujących (w takim przypadku może wystąpić iowaitzmiana metryki)

Xavier Lucas
źródło
Rozumiem, że średnia obciążeń obejmuje również zadania aktualnie wykonywane. Oznaczałoby to, że zdecydowanie możemy mieć wzrost średniej obciążenia bez faktycznej rywalizacji o procesory. A może się mylę / źle rozumiem?
K Erlandsson,
@KristofferE Masz całkowitą rację. Rzeczywista formuła to loadavg = taks uruchomione + zadania oczekujące (dla dostępnych rdzeni) + zadania zablokowane. Oznacza to, że możesz mieć obciążenie średnio 24, nie czekając ani nie blokując zadania, a tym samym mając „pełne wykorzystanie” lub pojemność sprzętu bez żadnych rywalizacji. Ponieważ wydawało ci się, że jesteś zdezorientowany co do średniej obciążenia i liczby uruchomionych procesów w porównaniu do użycia procesora, skoncentrowałem się głównie na wyjaśnieniach dotyczących tego, jak średnia obciążenie może nadal rosnąć przy tak małej liczbie uruchomionych procesów. Po ponownym przeczytaniu może nie być to tak jasne.
Xavier Lucas,
2

Średnia obciążeń obejmuje zadania, które są blokowane na IO dysku, dzięki czemu można łatwo korzystać z zerowego procesora i średnio 10 obciążeń, mając tylko 10 zadań, które próbują odczytać z bardzo wolnego dysku. Dlatego często zajęty serwer zaczyna psuć dysk, a wszystkie wyszukiwanie powoduje wiele zablokowanych zadań, zwiększając średnie obciążenie, a zużycie procesora spada, ponieważ wszystkie zadania są blokowane na dysku.

psusi
źródło
1

Chociaż odpowiedź Matthew Ife była bardzo pomocna i poprowadziła nas we właściwym kierunku, to nie dokładnie to spowodowało zachowanie w naszym przypadku. W naszym przypadku mamy wielowątkową aplikację Java, która korzysta z puli wątków, dlatego nie wykonujemy żadnej pracy przy tworzeniu rzeczywistych zadań.

Jednak faktyczna praca wykonywana przez wątki jest krótkotrwała i obejmuje oczekiwania na zamówienie lub synchronizację. Jak wspomina Matthew w swojej odpowiedzi, średnia obciążenia jest próbkowana przez system operacyjny, więc zadania krótkotrwałe mogą zostać pominięte.

Stworzyłem program Java, który odtworzył to zachowanie. Następująca klasa Java generuje obciążenie procesora na poziomie 28% (stos 650%) na jednym z naszych serwerów. Przy tym średnia wartość obciążenia wynosi około 1,3. Kluczem jest tutaj sleep () w wątku, bez niego obliczenie obciążenia jest prawidłowe.

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

}

Podsumowując, teoria jest taka, że ​​wątki w naszych aplikacjach często pracują bezczynnie, a następnie wykonują krótkotrwałą pracę, dlatego zadania nie są poprawnie próbkowane przez obliczenie średniej obciążenia.

K Erlandsson
źródło
0

Obciążenie średnie to średnia liczba procesów w kolejce procesora. Jest specyficzny dla każdego systemu, nie można powiedzieć, że jeden LA jest ogólnie wysoki we wszystkich systemach, a drugi jest niski. Masz więc 12 rdzeni, a aby LA znacznie się zwiększyło, liczba procesów musi być naprawdę wysoka.

Kolejne pytanie dotyczy tego, co należy rozumieć przez wykres „Wykorzystanie procesora”. Jeśli jest pobierany z SNMP, tak jak powinien być, a twoja implementacja SNMP jest net-snmp, to po prostu układa obciążenie procesora z każdego z 12 procesorów. Tak więc net-snmpcałkowita ilość obciążenia procesora wynosi 1200%.

Jeśli moje założenia są prawidłowe, użycie procesora nie wzrosło znacząco. Zatem LA nie wzrosło znacząco.

Drookie
źródło
Wykorzystanie procesora jest pobierane z wiersza mpstat all. Jestem całkiem pewien, że jest to średnia dla wszystkich procesorów, nie jest układana w stos. Na przykład, gdy wystąpi problem, top pokazuje 2000% użycia procesora dla jednego procesu. To jest skumulowane użycie.
K Erlandsson,
0

Scenariusz tutaj nie jest szczególnie nieoczekiwany, chociaż jest trochę niezwykły. To, czego Xavier dotyka, ale nie rozwija się zbytnio, polega na tym, że chociaż Linux (domyślnie) i większość odmian Uniksa implementuje wyprzedzające wielozadaniowość, na zdrowej maszynie, zadania rzadko są przejmowane. Każde zadanie ma przydzielony przedział czasu na zajęcie procesora, jest uprzednio opróżniane tylko wtedy, gdy przekracza ten czas, a inne zadania czekają na uruchomienie (pamiętaj, że ładunek zgłasza średnią liczbę procesów zarówno w CPU, jak i oczekujących na uruchomienie) . Przez większość czasu proces ustępuje, a nie zostaje przerwany.

(ogólnie rzecz biorąc, musisz się martwić tylko o obciążenie, gdy zbliży się ono do liczby procesorów - tj. kiedy program planujący zacznie wyprzedzać zadania).

jeśli nasze procesory są zajęte przez 75% czasu, czy nie powinniśmy widzieć wyższej średniej obciążenia?

Chodzi przede wszystkim o wzorzec aktywności, wyraźnie zwiększone wykorzystanie procesora przez niektóre zadania (najprawdopodobniej niewielka mniejszość) nie miało negatywnego wpływu na przetwarzanie innych zadań. Jeśli możesz wyodrębnić przetwarzane transakcje, spodziewam się, że zobaczysz nową grupę pojawiającą się podczas spowolnienia, podczas gdy nie wpłynie to na istniejący zestaw zadań.

aktualizacja

Jednym z powszechnych scenariuszy, w których może wystąpić wysoki procesor bez dużego wzrostu obciążenia, jest to, że zadanie wyzwala jedno (lub sekwencję) innych zadań, np. Po otrzymaniu żądania sieciowego, program obsługi kieruje żądanie do osobnego wątku, osobnego wątku następnie wykonuje asynchroniczne wywołania do innych procesów ... próbkowanie kolejki powoduje, że obciążenie jest zgłaszane niższe niż w rzeczywistości - ale nie rośnie liniowo z użyciem procesora - łańcuch uruchomionych zadań nie byłby możliwy bez zdarzenie początkowe, a ponieważ występują one (mniej więcej) sekwencyjnie, kolejka uruchamiania nie jest zawyżana.

symcbean
źródło
PO pierwotnie wskazywał, że zagregowany% procesora wynosił „2000%”, co sugeruje, że wiele zadań zużywa procesor zamiast jednego zajętego procesu. Gdyby było to stałe 2000% przez minutę, normalnie można by oczekiwać, że obciążenie będzie 20-krotne.
Matthew Ife
... w komentarzu, nie w pytaniu, i nie jest tego bardzo pewien. W przypadku braku opcji „WSZYSTKO”, mpstat zgłasza całkowite% użycia, a nie średnie. Ale to nie zmienia odpowiedzi - chodzi o wzorzec aktywności.
symcbean
Jestem w 100% pewien, że wykorzystanie procesora, które widzimy na wykresie, to „średnia na procesor”. Mpstat jest uruchamiany bez WSZYSTKICH, ale to pomija tylko informacje na temat procesora, allwiersz nadal pokazuje średnią na procesor. Wyjaśnię to pytanie.
K Erlandsson,
Czy mógłbyś proszę nieco rozwinąć swoją ostatnią sekcję? Nie rozumiem, co masz na myśli, podczas gdy część mojego pytania, które zacytowałeś, jest częścią, którą mam największe problemy ze zrozumieniem.
K Erlandsson,