2.- La CPU.

Si nuestro sistema está dimensionado de forma correcta no deberemos tener problemas de saturación en las CPUs, una forma sencilla de verificarlo es comprobar que el load average del equipo no supera el número de CPUs que tenemos.

Sin embargo es bastante frecuente que una aplicación se salga de su patrón de carga habitual, los motivos pueden ser de lo más variopintos. Un cambio de comportamiento de los usuarios, una actualización defectuosa, una select mal hecha, ... Cuando el tiempo de proceso requerido es superior al que pueden proporcionar nuestros procesadores los threads son puestos en las dispatch queues a la espera que quede una CPU libre, puedes leer una descripción completa del funcionamiento de estas aquí.

La perdida de performance por culpa de saturación de CPUs no es lineal, cuando se produce el S.O. debe gestionar las run queues, cambiar las prioridades de los procesos, intercambiar los procesos que se están ejecutandose en la CPU por otros más prioritarios, etc. Todo ello suele repercutir con un consumo en modo sistema más elevado, es decir, para solucionar nuestra escasez de tiempo de ejecución necesitamos tiempo de ejecución. En casos extremos puede darse el caso que el sistema llegue a consumir más tiempo en estas tareas que en ejecutar las aplicaciones.

Nuestro objetivo

Ante una situación de saturación de CPU debemos procurar identificar la aplicación cuyo consumo se ha salido del patrón habitual, en este artículo buscaremos identificar los Pids responsables para posteriormente analizarlos, trataremos la fase de análisis de los procesos en un artículo futuro.

Reconociendo el estado de saturación

El Usuario

A nivel de usuario se percibirá lentitud generalizada en todas las aplicaciones, posiblemente la shell le tarde más en responder de lo habitual. Aunque la descripción con la que nos puede llegar la incidencia será de lo más variopinta. Desde "error generalizado", pasando por "va lento", hasta lo más imaginativo que se te pueda ocurrir.

Los sintomas

Son varias las utilidades que nos permitirán determinar que existe una saturación en las cpus.

Vmstat

La columna r de la salida del vmstat indica el número de threads que se encuentran en las dispatch queues esperando a un CPU libre, si su número supera al de las CPUs de nuestro sistema estamos empezando a sufrir saturación, si lo duplica la performance se empezará a resentir notablemente.

root@box # vmstat 5 kthr memory page disk faults cpu r b w swap free re mf pi po fr de sr 2m m0 m1 m2 in sy cs us sy id 1 0 0 42157120 7573496 585 2219 1920 7 9 0 6 44 2 1 1 19612 34991 12905 42 15 43 0 0 0 41882080 7348816 546 2233 2175 0 0 0 0 35 0 0 0 12435 29385 6561 32 9 59 0 0 0 41882512 7344728 584 2393 2162 0 0 0 0 36 20 19 19 10922 32580 7231 28 9 63 0 0 0 41884936 7342656 628 2809 2174 0 0 0 0 35 0 0 0 11673 43611 8204 31 9 60 [...]

Lockstat

Si ejecutamos un #lookstat sleep 5 veremos multitud de bloqueos en los bloqueos exclusivos (mutex) de las dispatch queues, ya que el scheluder del sistema estará constantemente insertando nuevos threads, moviendo hilos de una cola a otra, etc:

root@box # lockstat sleep 5 [...] Count indv cuml rcnt spin Lock Caller ------------------------------------------------------------------------------- 1866 4% 80% 0.00 4 0x60002e39860 disp+0x84 1788 4% 83% 0.00 3 0x60002e39800 disp+0x84 1702 4% 87% 0.00 3 0x60002e39740 disp+0x84 [...]

Mpstat

Proporciona información por cada una de las CPUs, si nos centramos en la saturación deberíamos destacar:

root@box # mpstat 1 CPU minf mjf xcal intr ithr csw icsw migr smtx srw syscl usr sys wt idl 0 262 0 1096 374 7 1624 389 486 116 41 4546 44 13 0 43 1 272 0 1448 463 25 1978 451 551 134 40 4630 37 14 0 49 2 328 0 1154 620 268 1592 375 441 124 39 4515 44 15 0 41 3 257 0 1548 1758 1397 1348 323 422 153 37 3869 39 20 0 42 16 289 0 1224 842 535 1442 346 431 182 29 4256 43 15 0 42 17 297 0 1611 928 562 1708 388 479 208 28 4522 40 16 0 44 18 254 0 1088 350 7 1558 362 457 112 40 4420 45 13 0 42 19 255 0 1513 14420 264 1770 398 489 140 38 4395 40 15 0 45

icsw: Número de cambios de contexto involuntarios. Estos se producen cuando un thread es desalojado de la cpu porque agota su quantum o bien un thread con más prioridad pasa a estar disponible para ejecutarse. Un elevado valor puede ser debido a un exceso de threads en condición de ser ejecutado para el número de procesadores que disponemos.

migr: Número de threads en estado runnable que se han movido de la dispatch queue de un procesador a otro que estaba en ilde. Normalmente el sistema intenta que un thread siempre sea ejecutado en el mismo procesador ya que recuperar su contexto es menos costoso. Si el equipo se está viendo forzado continuamente a migrar hilos entre procesadores impactará en la performance. Puede ser debido a una alta carga de CPU o a una aplicación que escala mal en un entorno multiprocesador.

Quien está usando las CPUs, el diagnóstico.

Observar que las cpus del sistema están saturando es una tarea sencilla, sin embargo va acompañada de otra algo más compleja, quien es el responsable?

Prstat

Prstat proporciona muchísima información acerca del consumo de los procesos que se están ejecutando en nuestro sistema. Si lo ejecutamos con la opción -m nos proporcionará información acerca de los microestados de cada uno de ellos. Si añadimos la opción -L nos lo desglosará por thread.

root@box # prstat PID USERNAME SIZE RSS STATE PRI NICE TIME CPU PROCESS/NLWP 29921 oracle 16G 16G cpu17 40 0 1:32:53 7.4% oracle/1 24722 oracle 16G 16G sleep 60 0 0:13:25 4.6% oracle/11 5669 oracle 16G 16G sleep 60 0 0:19:29 2.3% oracle/11 27688 oracle 16G 16G sleep 48 2 1:44:05 1.7% oracle/11 28286 oracle 16G 16G sleep 60 0 0:07:51 1.3% oracle/11 5828 oracle 16G 16G sleep 59 0 115:22:45 1.2% oracle/258 27687 oracle 26M 22M cpu18 48 2 1:42:58 1.0% exp/1

root@box # prstat -mL PID USERNAME USR SYS TRP TFL DFL LCK SLP LAT VCX ICX SCL SIG PROCESS/LWPID 15485 oracle 61 2.2 1.4 0.0 0.0 0.0 27 8.5 281 1K 9K 0 oracle/1 5828 oracle 28 7.1 0.7 0.0 0.0 0.0 60 4.2 538 1K 4K 0 oracle/1 28141 oracle 33 1.8 0.4 0.0 0.0 0.0 64 1.1 50 540 3K 0 oracle/1 27315 oracle 30 1.4 0.9 0.0 0.0 0.0 64 4.1 75 1K 2K 1 oracle/1

En el capítulo anterior puedes leer una descripción de las columnas más significativas.

Sin embargo es importante no leer sólo números sino saber relacionar los distintos campos entre ellos. Si ejecutamos un prstat sin parámetros el listado aparece ordenado por consumo de CPU, por lo que los procesos que están en la parte superior son los mejores candidatos para ser investigados. Conviene observarlo durante un rato y determinar cuales mantienen una carga constante.

Uno de los problemas más frecuentes y difíciles de detectar son procesos que tienen una duración muy corta, estos pueden suponer una carga severa en el equipo. Sin embargo pueden pasar desapercibidos al comando prstat ya que refresca la pantalla cada pocos segundos. Si vemos un número elevado de cambios de contexto sin motivo aparente podríamos estar frente este problema.

Podemos usar el script shortlived.d del Dtrace ToolKit

Tracing... Hit Ctrl-C to stop. short lived processes: 0.643 secs total sample duration: 3.617 secs Total time by process name, sleep 6 ms cat 11 ms who 12 ms isainfo 19 ms date 21 ms echo 24 ms cut 29 ms hostname 34 ms awk 43 ms uname 58 ms kill 59 ms expr 116 ms init.cssd 128 ms Total time by PPID, 5559 3 ms 5547 4 ms 5613 4 ms 5638 7 ms 5640 7 ms 5572 8 ms 5642 9 ms 5551 10 ms 5624 31 ms 5591 36 ms 5558 37 ms 5579 58 ms 5612 59 ms 5546 61 ms 2935 135 ms

Continuando con el comando prstat, una vez tengamos claro los procesos con mayor consumo deberíamos ejecutarlo con la opción -m para ver los microestados de los procesos. En general, si hay saturación de las cpus, deberíamos observar un porcentaje de latencia (tiempo esperando CPU libre) elevado para todos los procesos.

root@box # prstat -m PID USERNAME USR SYS TRP TFL DFL LCK SLP LAT VCX ICX SCL SIG PROCESS/NLWP 29921 oracle 41 1.3 0.1 0.0 0.0 0.0 57 0.5 182 470 33K 0 oracle/1 27687 oracle 8.3 5.1 0.0 0.0 0.0 0.0 86 0.9 4K 120 13K 0 exp/1 5798 oracle 3.6 2.7 0.0 0.0 0.0 0.0 94 0.2 956 5 10K 8 oracle/1 5822 oracle 3.0 2.2 0.0 0.0 0.0 0.0 95 0.1 717 1 8K 3 oracle/1 6099 root 1.0 2.7 0.2 0.0 0.0 0.0 96 0.0 55 0 2K 0 sleep/1 5783 oracle 1.7 1.5 0.0 0.0 0.0 0.0 97 0.1 736 76 6K 198 oracle/1

Un buen dato para ver que procesos generan mucha carga es el número de llamadas a sistema (columna SCL), lo normal es que vaya acompañado de un % elevado de tiempo en modo sistema.

Conclusión

Después de estas comprobaciones deberemos tener una pequeña lista de pid que merece la atención analizar detenidamente, en artículos posteriores veremos como hacer un análisis detallado de estos procesos.

Creative Commons License
Esta obra está bajo una licencia de Creative Commons.