GNU/Linux >> Tutoriales Linux >  >> Linux

Alta utilización de la CPU pero bajo promedio de carga

Solución 1:

Al menos en Linux, el promedio de carga y la utilización de la CPU son en realidad dos cosas diferentes. El promedio de carga es una medida de cuántas tareas están esperando en una cola de ejecución del kernel (no solo el tiempo de CPU sino también la actividad del disco) durante un período de tiempo. La utilización de la CPU es una medida de cuán ocupada está la CPU en este momento. La mayor carga a la que un solo subproceso de CPU fijado al 100 % durante un minuto puede "contribuir" al promedio de carga de 1 minuto es 1. Una CPU de 4 núcleos con hiperprocesamiento (8 núcleos virtuales) todo al 100 % durante 1 minuto contribuiría con 8 a el promedio de carga de 1 minuto.

A menudo, estos dos números tienen patrones que se correlacionan entre sí, pero no puedes pensar en ellos como iguales. Puede tener una carga alta con una utilización de CPU de casi el 0 % (como cuando tiene muchos datos de E/S atascados en un estado de espera) y puede tener una carga de 1 y 100 % de CPU, cuando tiene un proceso de subproceso único en ejecución inclinación completa. Además, durante breves períodos de tiempo, puede ver la CPU cerca del 100 %, pero la carga aún está por debajo de 1 porque las métricas promedio aún no se han "alcanzado".

He visto un servidor con una carga de más de 15,000 (sí, realmente no es un error tipográfico) y un porcentaje de CPU cercano al 0%. Ocurrió porque un recurso compartido de Samba estaba teniendo problemas y muchos clientes comenzaron a quedarse atascados en un estado de espera de E/S. Lo más probable es que si ve un número de carga alto regular sin actividad de CPU correspondiente, tiene algún tipo de problema de almacenamiento. En las máquinas virtuales, esto también puede significar que hay otras VM que compiten fuertemente por los recursos de almacenamiento en el mismo host de VM.

La carga alta tampoco es necesariamente algo malo, la mayoría de las veces solo significa que el sistema se está utilizando a su máxima capacidad o tal vez está más allá de su capacidad para mantenerse al día (si el número de carga es mayor que el número de núcleos del procesador). En un lugar en el que solía ser administrador de sistemas, tenían a alguien que observaba el promedio de carga en su sistema principal más de cerca que Nagios. Cuando la carga era alta, me llamaban las 24 horas del día, los 7 días de la semana, más rápido de lo que podrías decir SMTP. La mayor parte del tiempo nada estaba realmente mal, pero asociaban el número de carga con algo que estaba mal y lo observaban como un halcón. Después de verificar, mi respuesta generalmente fue que el sistema solo estaba haciendo su trabajo. Por supuesto, este fue el mismo lugar donde la carga aumentó más de 15000 (aunque no es el mismo servidor), por lo que a veces significa que algo anda mal. Tienes que considerar el propósito de tu sistema. Si es un caballo de batalla, espere que la carga sea naturalmente alta.

Solución 2:

La carga es un número muy engañoso. Tómalo con pinzas.

Si genera muchas tareas en una sucesión muy rápida que se completan muy rápidamente, la cantidad de procesos en la cola de ejecución es demasiado pequeña para registrar la carga para ellos (el kernel cuenta la carga una vez cada cinco segundos).

Considere este ejemplo, en mi host que tiene 8 núcleos lógicos, esta secuencia de comandos de python registrará un gran uso de CPU en la parte superior (alrededor del 85 %), pero casi ninguna carga.

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

Otra implementación, esta evita wait en grupos de 8 (lo que sesgaría la prueba). Aquí, el padre siempre intenta mantener la cantidad de hijos en la cantidad de CPU activas, por lo que estará mucho más ocupado que el primer método y, con suerte, será más preciso.

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

El motivo de este comportamiento es que el algoritmo dedica más tiempo a crear procesos secundarios que a ejecutar la tarea real (contando hasta 10000). Las tareas que aún no se han creado no pueden contar para el estado 'ejecutable', pero ocuparán %sys del tiempo de CPU a medida que se generen.

Entonces, la respuesta realmente podría ser en su caso que cualquier trabajo que se esté realizando genere una gran cantidad de tareas en rápida sucesión (subprocesos o procesos).

Solución 3:

Si el promedio de carga no aumenta mucho, significa que las especificaciones de su hardware y la naturaleza de las tareas que se van a procesar dan como resultado un buen rendimiento general, lo que evita que se acumulen en la cola de tareas durante algún tiempo.

Si hubiera un fenómeno de contención porque, por ejemplo, la complejidad promedio de la tarea es demasiado alta o el tiempo de procesamiento promedio de la tarea toma demasiados ciclos de CPU, entonces sí, la carga promedio aumentaría.

ACTUALIZACIÓN:

Puede que no esté claro en mi respuesta original, así que lo aclaro ahora:

La fórmula exacta del cálculo del promedio de carga es:loadvg = tasks running + tasks waiting (for cores) + tasks blocked .

Definitivamente puede tener un buen rendimiento y acercarse a un promedio de carga de 24 pero sin penalizar el tiempo de procesamiento de las tareas. Por otro lado, también puede tener de 2 a 4 tareas periódicas que no se completen lo suficientemente rápido, luego verá que la cantidad de tareas en espera (para ciclos de CPU) crece y eventualmente alcanzará un promedio de carga alto. Otra cosa que puede suceder es tener tareas que ejecutan operaciones de E/S sincrónicas pendientes y luego bloquear un núcleo, reducir el rendimiento y hacer que la cola de tareas en espera crezca (en ese caso, es posible que vea el iowait cambio de métrica)

Solución 4:

Si bien la respuesta de Matthew Ife fue muy útil y nos condujo en la dirección correcta, no fue exactamente lo que causó el comportamiento en nuestro caso. En nuestro caso, tenemos una aplicación Java de subprocesos múltiples que utiliza la agrupación de subprocesos, por lo que no se realiza ningún trabajo creando las tareas reales.

Sin embargo, el trabajo real que realizan los subprocesos es de corta duración e incluye esperas de E/S o esperas de sincronización. Como menciona Matthew en su respuesta, el sistema operativo muestrea el promedio de carga, por lo que las tareas de corta duración pueden pasarse por alto.

Hice un programa Java que reprodujo el comportamiento. La siguiente clase de Java genera una utilización de CPU del 28% (650% apilado) en uno de nuestros servidores. Al hacer esto, el promedio de carga es de aproximadamente 1,3. La clave aquí es sleep() dentro del hilo, sin él, el cálculo de la carga es correcto.

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

}

Para resumir, la teoría es que los subprocesos en nuestras aplicaciones están inactivos mucho y luego realizan un trabajo de corta duración, razón por la cual las tareas no se muestrean correctamente mediante el cálculo del promedio de carga.

Solución 5:

El promedio de carga incluye tareas que están bloqueadas en el disco IO, por lo que puede tener fácilmente una utilización de CPU cero y un promedio de carga de 10 simplemente teniendo 10 tareas que intentan leer desde un disco muy lento. Por lo tanto, es común que un servidor ocupado comience a agitar el disco y toda la búsqueda provoque muchas tareas bloqueadas, lo que aumenta el promedio de carga, mientras que el uso de la CPU disminuye, ya que todas las tareas están bloqueadas en el disco.


Linux
  1. CPU alta causada por Sophos en Windows

  2. Comprender el promedio de carga del sistema operativo y la cola de ejecución/cola bloqueada en términos de utilización de la CPU en Linux

  3. Jenkins ejecutándose con un uso de CPU muy alto

  4. Carga del servidor alta, CPU inactiva. NFS la causa?

  5. ¿Qué significa 'agradable' en los gráficos de utilización de la CPU?

Cómo crear una carga de CPU del 100 % en un sistema Linux

Comprender el promedio de carga en cPanel.

Uso elevado de la CPU:la instalación de SQL no se ha completado

¿Qué es el promedio de carga en Linux?

Cómo verificar el uso o la utilización de la CPU de Linux

¿Hasta dónde puede llegar la carga del sistema?