Высокая загрузка ЦП, но средняя нагрузка низкая


28

Мы сталкиваемся со странным поведением, когда мы видим высокую загрузку процессора, но довольно низкую среднюю нагрузку.

Поведение лучше всего иллюстрируется следующими графиками из нашей системы мониторинга.

Загрузка и загрузка процессора

Примерно в 11:57 загрузка ЦП снижается с 25% до 75%. Средняя нагрузка существенно не изменилась.

Мы запускаем серверы с 12 ядрами с 2 гиперпотоками каждый. ОС видит это как 24 процессора.

Данные об использовании ЦП собираются путем запуска /usr/bin/mpstat 60 1каждую минуту. Данные для allстроки и %usrстолбца показаны на диаграмме выше. Я уверен, что это показывает среднее значение для каждого процессора, а не «сложенное» использование. В то время как мы видим 75% загрузки на графике, мы видим процесс, показывающий использование около 2000% «стекового» процессора top.

Среднее значение нагрузки берется с /proc/loadavgкаждой минуты.

uname -a дает:

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

Линукс дист есть Red Hat Enterprise Linux Server release 6.3 (Santiago)

Мы запускаем пару веб-приложений на Java при довольно большой нагрузке на машины, примерно 100 запросов / с на машину.

Если я правильно интерпретирую данные об использовании ЦП, то при использовании ЦП 75% это означает, что наши ЦП выполняют процесс в среднем 75% времени. Однако, если наши процессоры заняты 75% времени, разве мы не видим более высокую среднюю нагрузку? Как процессоры могут быть заняты на 75%, в то время как у нас есть только 2-4 задания в очереди выполнения?

Правильно ли мы интерпретируем наши данные? Что может вызвать это поведение?


Система мониторинга показывает нормированную загрузку процессора (нагрузка / #CPU)? Обычную загрузку ЦП Linux трудно сравнивать в разных системах с различным количеством ядер / процессоров, поэтому некоторые инструменты используют вместо этого нормированную загрузку ЦП.
Брайан

Вы имеете в виду деление каждой точки данных на количество процессоров? Т.е. loadavg / 24 в нашем случае? Я могу легко создать такую ​​диаграмму из данных, если это поможет.
К Эрландссон

Я предполагал, что ваша диаграмма, возможно, уже показывает это.
Брайан

Ах, извините за недопонимание вас. Это было бы хорошим объяснением, но, к сожалению, показывается средняя загрузка системы. Я только трижды проверил.
К Эрландссон

Ответы:


51

По крайней мере, в Linux средняя загрузка и загрузка ЦП - это две разные вещи. Средняя загрузка - это измерение количества задач, ожидающих в очереди выполнения ядра (не только процессорного времени, но и дисковой активности) за период времени. Загрузка ЦП является мерой того, насколько ЦП сейчас занят. Наибольшая нагрузка, которую один поток ЦП привязал на 100% в течение одной минуты, может "внести" вклад в среднюю загрузку за 1 минуту: 1. 4-ядерный ЦП с гиперпоточностью (8 виртуальных ядер), все при 100% в течение 1 минуты, будет способствовать 8 средняя загрузка за 1 минуту.

Часто эти два числа имеют шаблоны, которые соотносятся друг с другом, но вы не можете думать о них как об одном и том же. Вы можете иметь высокую нагрузку с почти 0% загрузкой ЦП (например, когда у вас много данных ввода-вывода, застрявших в состоянии ожидания), и вы можете иметь нагрузку на 1 и 100% ЦП, когда у вас запущен однопоточный процесс полный наклон. Также в течение коротких промежутков времени вы можете видеть, что ЦП приближается к 100%, но нагрузка все еще ниже 1, потому что средние показатели еще не «догнали».

Я видел, что сервер имеет нагрузку более 15000 (да, на самом деле это не опечатка), а загрузка ЦП близка к 0%. Это произошло из-за проблем с общим ресурсом Samba, и многие клиенты начали зависать в состоянии ожидания ввода-вывода. Скорее всего, если вы видите обычный высокий номер загрузки без соответствующей загрузки процессора, у вас возникла проблема с хранением какого-либо рода. На виртуальных машинах это также может означать, что другие виртуальные машины сильно конкурируют за ресурсы хранения на том же хосте виртуальных машин.

Высокая нагрузка также не обязательно является плохой вещью, в большинстве случаев она просто означает, что система используется на полную мощность или, возможно, не в состоянии поддерживать ее (если число загрузок превышает число ядер процессора). В месте, где я раньше был системным администратором, у них был кто-то, кто следил за средней нагрузкой в ​​своей основной системе ближе, чем Нагиос. Когда нагрузка была высокой, они звонили мне круглосуточно быстрее, чем вы могли бы сказать SMTP. Большую часть времени на самом деле все было не так, но они связывали номер загрузки с чем-то не так и смотрели на него как на ястреба. После проверки я обычно отвечал, что система просто выполняет свою работу. Конечно, это было то же самое место, где нагрузка превысила 15000 (хотя не тот же сервер), поэтому иногда это означает, что что-то не так. Вы должны рассмотреть цель вашей системы. Если это рабочая лошадка, то ожидайте, что нагрузка будет естественно высокой.


Как вы имеете в виду, что у меня может быть загрузка 1 и 100% CPU с однопоточным процессом? О каких темах ты говоришь? Если мы рассмотрим наши процессы Java, у них есть тонны потоков, но я предполагал, что потоки рассматривались как процессы с точки зрения ОС (в конце концов, они имеют отдельные PID в Linux). Может ли быть так, что один многопоточный Java-процесс считается только одной задачей с точки зрения средней нагрузки?
K Erlandsson

Я только что провел тест самостоятельно, потоки в Java-процессе вносят вклад в среднюю нагрузку, как если бы они были отдельными процессами (то есть класс Java, который запускает 10 потоков в цикле занятого ожидания, дает мне нагрузку, близкую к 10). Буду признателен за разъяснение о резьбовом процессе, который вы упомянули выше. Спасибо!
К Эрландссон

Я имею в виду, если у вас не многопоточный процесс (т. Е. Тот, который использует только один процессор за раз). Например, если вы просто пишете простую программу на C, которая выполняет занятый цикл, она работает только в одном потоке и использует только 1 процессор за раз.
Дельтарай

Вся информация, которую я нашел, говорит о том, что потоки считаются отдельными процессами, если смотреть из ядра и при расчете нагрузки. Следовательно, я не вижу, как у меня может быть многопоточный процесс при полном наклоне, приводящий к 1 загрузке и 100% ЦП в многопроцессорной системе. Не могли бы вы помочь мне понять, что вы имеете в виду?
К Эрландссон

Для тех, кто ищет подробности: «Средние показатели загрузки Linux: разгадывание тайны» Брендана Грегга, у меня были ответы на все вопросы, которые мне когда-либо были нужны.
Николай

24

Загрузка очень обманчиво. Возьми это с зерном соли.

Если вы создаете много задач в очень быстрой последовательности, которая завершается очень быстро, число процессов в очереди выполнения слишком мало, чтобы регистрировать нагрузку для них (ядро считает нагрузку каждые пять секунд).

Рассмотрим этот пример, на моем хосте, который имеет 8 логических ядер, этот скрипт на python регистрирует высокую загрузку ЦП сверху (около 85%), но почти без нагрузки.

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

Другая реализация, в которой этого избегают waitв группах по 8 (что исказило бы тест). Здесь родитель всегда пытается сохранить количество дочерних элементов при количестве активных процессоров, так что это будет намного более трудоемким, чем первый метод, и, будем надеяться, более точным.

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

Причиной такого поведения является то, что алгоритм тратит больше времени на создание дочерних процессов, чем на выполнение фактической задачи (считая до 10000). Задачи, которые еще не созданы, не могут учитываться в состоянии «работоспособность», но будут занимать% sys по времени ЦП по мере их появления.

Таким образом, ответ может быть действительно в вашем случае, что независимо от того, какая работа выполняется, порождает большое количество задач в быстрой последовательности (потоки или процессы).


Спасибо за предложение. Диаграмма в моем вопросе показывает% пользовательского времени (системное время процессора исключено, мы видим только очень небольшое увеличение системного времени). В любом случае, могут ли многие маленькие задачи быть объяснением? Если средняя нагрузка выбирается каждые 5 секунд, чаще ли выбираются данные об использовании процессора, представленные mpstat?
К Эрландссон

Я не знаком с тем, как там выполняется выборка процессора. Никогда не читайте исходный код ядра относительно этого. В моем примере% usr было 70% +, а% sys было 15%.
Мэтью Ифе

Хорошие примеры!
Ксавье Лукас

5

Если средняя нагрузка не сильно увеличивается, то это просто означает, что технические характеристики вашего оборудования и характер задач, которые должны быть обработаны, приводят к хорошей общей пропускной способности, что позволяет избежать их накопления в очереди задач на некоторое время.

Если бы был феномен раздора, потому что, например, средняя сложность задачи слишком высока или среднее время обработки задачи занимает слишком много циклов ЦП, то да, средняя нагрузка увеличилась бы.

ОБНОВИТЬ :

Это может быть неясно в моем первоначальном ответе, поэтому я уточняю сейчас:

Точная формула расчета средней нагрузки является: loadvg = tasks running + tasks waiting (for cores) + tasks blocked.

Вы можете определенно иметь хорошую пропускную способность и приблизиться к средней загрузке 24, но без потери времени обработки задач. С другой стороны, у вас также может быть 2-4 периодических задач, которые не выполняются достаточно быстро, тогда вы увидите, что число ожидающих задач (для циклов ЦП) растет, и вы в конечном итоге достигнете высокой средней нагрузки. Еще одна вещь, которая может произойти - это выполнение задач, выполняющих незавершенные синхронные операции ввода-вывода, затем блокирование ядра, снижение пропускной способности и увеличение очереди ожидающих задач (в этом случае вы можете увидеть iowaitизменение метрики)


Насколько я понимаю, средняя загрузка также включает задачи, выполняемые в настоящее время. Это означало бы, что мы определенно можем увеличить среднюю нагрузку без фактической конкуренции за процессоры. Или я ошибаюсь / неправильно понимаю вас?
К Эрландссон

@KristofferE Вы совершенно правы. Фактическая формула: loadavg = такты выполнения + задачи, ожидающие (для доступных ядер) + задачи, заблокированные. Это означает, что вы можете иметь среднюю нагрузку 24, не ожидая или заблокировав задачу, таким образом, имея «полную загрузку» или вашу аппаратную емкость без каких-либо конфликтов. Поскольку вы, похоже, не понимали, насколько средняя нагрузка зависит от количества процессов, работающих с использованием ЦП, я в основном сфокусировала свой ответ на объяснениях того, как средняя нагрузка все еще может расти при столь малом количестве запущенных процессов в целом. Это может быть не совсем понятно после перечитывания.
Ксавье Лукас,

2

Средняя загрузка включает в себя задачи, заблокированные на дисковый ввод-вывод, поэтому вы можете легко использовать процессор без нуля и в среднем загрузить 10, просто имея 10 задач, которые все пытаются прочитать с очень медленного диска. Таким образом, занятый сервер обычно начинает перебивать диск, и все операции поиска приводят к большому количеству заблокированных задач, увеличивая среднюю загрузку, в то время как использование процессора падает, поскольку все задачи блокируются на диске.


1

Хотя ответ Мэтью Ифе был очень полезным и привел нас в правильном направлении, это было не совсем то, что вызвало поведение в нашем случае. В нашем случае у нас есть многопоточное Java-приложение, которое использует пул потоков, поэтому не выполняется никакой работы по созданию реальных задач.

Однако фактическая работа, которую выполняют потоки, недолговечна и включает в себя ожидания ввода-вывода или ожидания синхронизации. Как Мэтью упоминает в своем ответе, средняя загрузка выбирается ОС, поэтому недолговечные задачи могут быть пропущены.

Я сделал программу на Java, которая воспроизводила поведение. Следующий класс Java генерирует использование ЦП 28% (650% в стеке) на одном из наших серверов. При этом средняя нагрузка составляет около 1,3. Ключевым моментом здесь является sleep () внутри потока, без которого вычисление нагрузки корректно.

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

}

Подводя итог, можно сказать, что теория состоит в том, что потоки в наших приложениях много простаивают, а затем выполняют недолговечную работу, поэтому задачи не корректно выбираются при расчете средней нагрузки.


0

Средняя загрузка - это среднее количество процессов в очереди ЦП. Это специфично для каждой системы, вы не можете сказать, что один LA обычно высок во всех системах, а другой низкий. Таким образом, у вас есть 12 ядер, и для того, чтобы LA значительно увеличился, количество процессов должно быть действительно высоким.

Другой вопрос, что подразумевается под графиком «Загрузка ЦП». Если он взят из SNMP, как и должно быть, и ваша реализация SNMP net-snmp, то просто стеков загрузки ЦП от каждого из ваших 12 ЦП. Так что для net-snmpобщего объема загрузки процессора это 1200%.

Если мои предположения верны, то загрузка ЦП существенно не увеличилась. Таким образом, LA значительно не увеличился.


Использование процессора взято из строки mpstat all. Я вполне уверен, что это среднее значение для всех процессоров, оно не суммируется. Например, когда возникает проблема, top показывает 2000% загрузки ЦП для одного процесса. Это сложное использование.
К Эрландссон

0

Сценарий здесь не особенно неожиданный, хотя он немного необычный. Что касается Ксавье, но не развивается, так это то, что, хотя Linux (по умолчанию) и большинство разновидностей Unix реализуют упреждающую многозадачность, на здоровой машине задачи редко будут иметь приоритет. Каждой задаче выделяется временной интервал для заполнения ЦП, он имеет преимущественную силу, если он превышает это время, и есть другие задачи, ожидающие выполнения (обратите внимание, что загрузка сообщает о среднем количестве процессов как в ЦП, так и ожидающих запуска) , Большую часть времени процесс даст результат, а не будет прерван.

(в общем случае вам нужно беспокоиться о нагрузке только тогда, когда она приближается к числу процессоров - т.е. когда планировщик начинает выполнять приоритетные задачи).

если наши процессоры заняты 75% времени, разве мы не видим более высокую среднюю нагрузку?

Все дело в характере деятельности, явно увеличенная загрузка ЦП некоторыми задачами (скорее всего небольшая доля) не оказала отрицательного влияния на обработку других задач. Если бы вы могли изолировать обрабатываемые транзакции, я бы ожидал, что во время замедления вы увидите новую группу, в то время как существующий набор задач не был затронут.

Обновить

Один из распространенных сценариев, когда высокая загрузка ЦП может происходить без значительного увеличения нагрузки, - это когда задача запускает одну (или последовательность) других задач, например, при получении сетевого запроса, обработчик направляет запрос в отдельный поток, отдельный поток затем делает некоторые асинхронные вызовы другим процессам .... выборка из очереди выполнения приводит к тому, что нагрузка сообщается ниже, чем она есть на самом деле - но она не возрастает линейно с использованием ЦП - цепочка запускаемых задач не была бы запущена без начальное событие, и поскольку они происходят (более или менее) последовательно, очередь выполнения не раздувается.


Первоначально OP предоставлял указания, что совокупный% ЦП составлял «2000%», предполагая, что есть много задач, использующих ЦП, а не только один занятый процесс. Если бы это были постоянные 2000% в течение минуты, вы обычно ожидали бы, что нагрузка будет 20-ти минутной.
Мэтью Иф

... в комментарии, а не в вопросе, и он не очень уверен в этом. В отсутствие опции «ALL» mpstat сообщает об общем процентном использовании, а не о среднем. Но это не меняет ответа - речь идет о модели деятельности.
Symcbean

Я на 100% уверен, что загрузка процессора, которую мы видим на графике, - это «среднее значение на процессор». Mpstat запускается без ALL, но при этом пропускается только информация для каждого процессора, в allстроке по-прежнему отображается среднее значение для каждого процессора. Я уточню вопрос.
К Эрландссон

Не могли бы вы, пожалуйста, уточнить ваш последний раздел немного? Я не понимаю, что вы имеете в виду, в то время как часть моего вопроса, которую вы упомянули, является частью, которую мне трудно понять.
К Эрландссон
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.