Robar: quién roba tiempo de CPU de las máquinas virtuales

Robar: quién roba tiempo de CPU de las máquinas virtuales

¡Hola! Quiero contarles en términos simples sobre la mecánica del robo dentro de las máquinas virtuales y sobre algunos artefactos no obvios que logramos descubrir durante su investigación, en los que tuve que sumergirme como director técnico de una plataforma en la nube. Soluciones en la nube Mail.ru. La plataforma se ejecuta en KVM.

El tiempo de robo de CPU es el tiempo durante el cual la máquina virtual no recibe recursos del procesador para su ejecución. Este tiempo sólo se cuenta en sistemas operativos invitados en entornos de virtualización. Las razones de adónde van a parar estos recursos más asignados, como en la vida, son muy vagas. Pero decidimos resolverlo e incluso realizamos una serie de experimentos. No es que ahora sepamos todo sobre el robo, pero ahora te contamos algo interesante.

1. ¿Qué es robar?

Entonces, el robo es una métrica que indica una falta de tiempo de procesador para los procesos dentro de una máquina virtual. Como se describe en el parche del kernel KVMEl sigilo es el tiempo durante el cual el hipervisor ejecuta otros procesos en el sistema operativo host aunque haya puesto en cola el proceso de la máquina virtual para su ejecución. Es decir, el robo se calcula como la diferencia entre el momento en que el proceso está listo para ejecutarse y el momento en que al proceso se le asigna tiempo de procesador.

El kernel de la máquina virtual recibe la métrica de robo del hipervisor. Al mismo tiempo, el hipervisor no especifica exactamente qué otros procesos está ejecutando, simplemente dice "mientras estoy ocupado, no puedo darte tiempo". En KVM, se ha agregado soporte para el cálculo de robo. parches. Hay dos puntos clave aquí:

  • La máquina virtual aprende sobre el robo desde el hipervisor. Es decir, desde el punto de vista de las pérdidas, para los procesos en la propia máquina virtual esta es una medida indirecta que puede estar sujeta a diversas distorsiones.
  • El hipervisor no comparte información con la máquina virtual sobre qué más está haciendo; lo principal es que no le dedica tiempo. Debido a esto, la máquina virtual por sí sola no puede detectar distorsiones en el indicador de robo, lo que podría evaluarse por la naturaleza de los procesos en competencia.

2. ¿Qué afecta el robo?

2.1. Cálculo de robo

Básicamente, el robo se calcula aproximadamente igual que el tiempo de utilización normal de la CPU. No hay mucha información sobre cómo se considera el reciclaje. Probablemente porque la mayoría de la gente considera que esta pregunta es obvia. Pero aquí también hay trampas. Para familiarizarse con este proceso, puede leer artículo de Brendan Gregg: aprenderá sobre muchos matices al calcular la utilización y sobre situaciones en las que este cálculo será erróneo por las siguientes razones:

  • El procesador se sobrecalienta, lo que provoca que se salten ciclos.
  • Activa/desactiva el turbo boost, que cambia la frecuencia del reloj del procesador.
  • Un cambio en la duración del intervalo de tiempo que se produce cuando se utilizan tecnologías de ahorro de energía del procesador como SpeedStep.
  • El problema de calcular el promedio: estimar la utilización de un minuto en un 80% puede ocultar una explosión a corto plazo del 100%.
  • Un bloqueo de giro hace que se recupere el procesador, pero el proceso del usuario no ve ningún progreso en su ejecución. Como resultado, la utilización calculada del procesador por parte del proceso será del cien por cien, aunque el proceso no consumirá físicamente tiempo del procesador.

No he encontrado un artículo que describa un cálculo similar para el robo (si lo sabes, compártelo en los comentarios). Pero, a juzgar por el código fuente, el mecanismo de cálculo es el mismo que para el reciclaje. Simplemente, se agrega otro contador en el kernel, directamente para el proceso KVM (proceso de máquina virtual), que cuenta la duración del proceso KVM esperando el tiempo de CPU. El contador toma información sobre el procesador de su especificación y verifica si el proceso de la máquina virtual utiliza todos sus ticks. Si eso es todo, entonces asumimos que el procesador sólo estaba ocupado con el proceso de la máquina virtual. De lo contrario, informamos que el procesador estaba haciendo otra cosa, apareció un robo.

El proceso de conteo de robos está sujeto a los mismos problemas que el conteo de reciclaje regular. No quiere decir que estos problemas aparezcan con frecuencia, pero parecen desalentadores.

2.2. Tipos de virtualización en KVM

En términos generales, existen tres tipos de virtualización, todos ellos compatibles con KVM. El mecanismo de ocurrencia del robo puede depender del tipo de virtualización.

Emisión. En este caso, el funcionamiento del sistema operativo de la máquina virtual con dispositivos hipervisores físicos es algo como esto:

  1. El sistema operativo invitado envía un comando a su dispositivo invitado.
  2. El controlador del dispositivo invitado recibe el comando, genera una solicitud para el BIOS del dispositivo y la envía al hipervisor.
  3. El proceso del hipervisor traduce un comando en otro para el dispositivo físico, haciéndolo, entre otras cosas, más seguro.
  4. El controlador del dispositivo físico acepta el comando modificado y lo envía al propio dispositivo físico.
  5. Los resultados de la ejecución de comandos regresan por el mismo camino.

La ventaja de la traducción es que permite emular cualquier dispositivo y no requiere una preparación especial del kernel del sistema operativo. Pero por esto hay que pagar, ante todo, por la velocidad.

Virtualización de hardware. En este caso, el dispositivo a nivel de hardware comprende los comandos del sistema operativo. Esta es la mejor y más rápida manera. Pero, lamentablemente, no es compatible con todos los dispositivos físicos, hipervisores y sistemas operativos invitados. Actualmente, los principales dispositivos que soportan la virtualización de hardware son los procesadores.

Paravirtualización. La opción más común para la virtualización de dispositivos en KVM y, en general, el modo de virtualización más común para sistemas operativos invitados. Su peculiaridad es que el trabajo con algunos subsistemas del hipervisor (por ejemplo, con la red o la pila de discos) o la asignación de páginas de memoria se realiza mediante la API del hipervisor, sin traducir comandos de bajo nivel. La desventaja de este método de virtualización es que el kernel del sistema operativo invitado debe modificarse para que pueda comunicarse con el hipervisor mediante esta API. Pero esto normalmente se soluciona instalando controladores especiales en el sistema operativo invitado. En KVM esta API se llama API virtio.

Con la paravirtualización, en comparación con la transmisión, la ruta al dispositivo físico se reduce significativamente al enviar comandos directamente desde la máquina virtual al proceso del hipervisor en el host. Esto le permite acelerar la ejecución de todas las instrucciones dentro de la máquina virtual. En KVM, esto lo hace la API virtio, que solo funciona para ciertos dispositivos, como una red o un adaptador de disco. Es por eso que los controladores virtio se instalan dentro de las máquinas virtuales.

La desventaja de esta aceleración es que no todos los procesos que se ejecutan dentro de la máquina virtual permanecen dentro de ella. Esto crea algunos efectos especiales que pueden provocar que aparezcan al robar. Recomiendo comenzar un estudio detallado de este tema con Una API para E/S virtual: virtio.

2.3. Programación "justa"

Una máquina virtual en un hipervisor es, de hecho, un proceso ordinario que obedece las leyes de programación (distribución de recursos entre procesos) en el kernel de Linux, así que echémosle un vistazo más de cerca.

Linux utiliza el llamado CFS, Completely Fair Scheduler, que se ha convertido en el programador predeterminado desde el kernel 2.6.23. Para comprender este algoritmo, puede leer la arquitectura del kernel de Linux o el código fuente. La esencia de CFS es distribuir el tiempo del procesador entre procesos en función de la duración de su ejecución. Cuanto más tiempo de CPU requiere un proceso, menos tiempo de CPU recibe. Esto garantiza que todos los procesos se ejecuten de forma "justa", de modo que un proceso no ocupe constantemente todos los procesadores y otros procesos también puedan ejecutarse.

A veces este paradigma conduce a artefactos interesantes. Los usuarios de Linux desde hace mucho tiempo probablemente recuerden la congelación de un editor de texto normal en un escritorio mientras ejecutaban aplicaciones que consumían muchos recursos, como un compilador. Esto sucedió porque las tareas que no consumían muchos recursos en las aplicaciones de escritorio competían con tareas que consumían muchos recursos, como el compilador. CFS cree que esto es injusto, por lo que periódicamente detiene el editor de texto y deja que el procesador se encargue de las tareas del compilador. Esto se corrigió mediante un mecanismo. sched_autogrupo, pero se mantuvieron muchas otras características de la distribución del tiempo del procesador entre tareas. En realidad, esta no es una historia sobre lo mal que está todo en CFS, sino un intento de llamar la atención sobre el hecho de que la distribución "justa" del tiempo del procesador no es la tarea más trivial.

Otro punto importante en el planificador es la preferencia. Esto es necesario para eliminar el proceso de risita del procesador y dejar que otros trabajen. El proceso de expulsión se llama cambio de contexto. En este caso se conserva todo el contexto de la tarea: el estado de la pila, registros, etc., tras lo cual el proceso se envía a espera y otro ocupa su lugar. Esta es una operación costosa para el sistema operativo y rara vez se usa, pero no tiene nada de malo. El cambio de contexto frecuente puede indicar un problema en el sistema operativo, pero normalmente es continuo y no indica nada en particular.

Se necesita una historia tan larga para explicar un hecho: cuantos más recursos de procesador intente consumir un proceso en un programador honesto de Linux, más rápido se detendrá para que otros procesos también puedan funcionar. Si esto es correcto o no es una cuestión compleja que puede resolverse de manera diferente bajo diferentes cargas. En Windows, hasta hace poco, el programador se centraba en el procesamiento prioritario de las aplicaciones de escritorio, lo que podía provocar que los procesos en segundo plano se congelaran. Sun Solaris tenía cinco clases diferentes de programadores. Cuando lanzamos la virtualización, agregamos una sexta, Programador de participación justa, porque los cinco anteriores no funcionaron adecuadamente con la virtualización de Zonas Solaris. Recomiendo comenzar un estudio detallado de este tema con libros como Internos de Solaris: Solaris 10 y OpenSolaris Kernel Architecture o Entendiendo el Kernel de Linux.

2.4. ¿Cómo monitorear el robo?

Monitorear el robo dentro de una máquina virtual, como cualquier otra métrica del procesador, es simple: puede usar cualquier herramienta de métricas del procesador. Lo principal es que la máquina virtual esté en Linux. Por alguna razón, Windows no proporciona esta información a sus usuarios. 🙁

Robar: quién roba tiempo de CPU de las máquinas virtuales
Salida del comando superior: detalles de la carga del procesador, en la columna de la derecha - robar

La dificultad surge al intentar obtener esta información del hipervisor. Puede intentar predecir el robo en la máquina host, por ejemplo, utilizando el parámetro Promedio de carga (LA), el valor promedio de la cantidad de procesos esperando en la cola de ejecución. El método para calcular este parámetro no es simple, pero en general, si LA normalizado por el número de subprocesos del procesador es mayor que 1, esto indica que el servidor Linux está sobrecargado con algo.

¿A qué esperan todos estos procesos? La respuesta obvia es el procesador. Pero la respuesta no es del todo correcta, porque a veces el procesador está libre, pero LA se sale de escala. Recordar Cómo cae NFS y cómo crece LA. Lo mismo puede ocurrir con un disco y otros dispositivos de entrada/salida. Pero, de hecho, los procesos pueden esperar el final de cualquier bloqueo, ya sea físico, asociado con un dispositivo de E/S, o lógico, como un mutex. Esto también incluye el bloqueo a nivel de hardware (la misma respuesta del disco) o lógica (las llamadas primitivas de bloqueo, que incluyen un montón de entidades, mutex adaptables y spin, semáforos, variables de condición, bloqueos rw, bloqueos ipc). ...).

Otra característica de LA es que se considera un sistema operativo promedio. Por ejemplo, 100 procesos compiten por un archivo y luego LA=50. Un valor tan grande parecería indicar que el sistema operativo es malo. Pero para otros códigos mal escritos, este puede ser un estado normal, a pesar de que solo es malo y otros procesos en el sistema operativo no se ven afectados.

Debido a este promedio (y en no menos de un minuto), determinar algo mediante el indicador LA no es la tarea más gratificante, con resultados muy inciertos en casos específicos. Si intentas resolverlo, encontrarás que los artículos en Wikipedia y otros recursos disponibles describen sólo los casos más simples, sin una explicación profunda del proceso. Envío a todos los que estén interesados, de nuevo, aquí para Brendan Gregg  - siga los enlaces a continuación. ¿Quién es demasiado vago para hablar inglés? traducción de su popular artículo sobre Los Ángeles.

3. Efectos especiales

Ahora veamos los principales casos de robo que encontramos. Le diré cómo se derivan de todo lo anterior y cómo se relacionan con los indicadores del hipervisor.

Reciclaje. El más sencillo y común: se ha reutilizado el hipervisor. De hecho, hay muchas máquinas virtuales en ejecución, un alto consumo de procesador dentro de ellas, mucha competencia, la utilización de LA es superior a 1 (normalizada por subprocesos del procesador). Todo dentro de todas las máquinas virtuales se ralentiza. El robo transmitido desde el hipervisor también está aumentando, es necesario redistribuir la carga o desconectar a alguien. En general, todo es lógico y comprensible.

Paravirtualización versus instancias únicas. Sólo hay una máquina virtual en el hipervisor; consume una pequeña parte de ella, pero produce una gran carga de E/S, por ejemplo en el disco. Y de alguna parte aparece un pequeño robo, hasta un 10% (como lo demuestran varios experimentos).

El caso es interesante. El robo aparece aquí precisamente por el bloqueo a nivel de controladores paravirtualizados. Se crea una interrupción dentro de la máquina virtual, la procesa el controlador y la envía al hipervisor. Debido al manejo de interrupciones en el hipervisor, para la máquina virtual parece una solicitud enviada, está lista para su ejecución y está esperando al procesador, pero no se le da tiempo de procesador. La chica virtual piensa que este tiempo le ha sido robado.

Esto sucede en el momento en que se envía el búfer, ingresa al espacio del kernel del hipervisor y comenzamos a esperarlo. Aunque, desde el punto de vista de la máquina virtual, debería volver inmediatamente. Por tanto, según el algoritmo de cálculo del robo, este tiempo se considera robado. Lo más probable es que en esta situación existan otros mecanismos (por ejemplo, procesar otras llamadas al sistema), pero no deberían ser muy diferentes.

Programador versus máquinas virtuales altamente cargadas. Cuando una máquina virtual sufre más robos que otras, esto se debe al programador. Cuanto más carga un proceso el procesador, antes lo expulsará el programador para que los demás también puedan trabajar. Si la máquina virtual consume poco, difícilmente verá robos: su proceso honestamente se quedó esperando, debemos darle más tiempo. Si una máquina virtual produce la carga máxima en todos sus núcleos, a menudo la expulsan del procesador y tratan de no dedicarle mucho tiempo.

Es aún peor cuando los procesos dentro de la máquina virtual intentan obtener más procesador porque no pueden hacer frente al procesamiento de datos. Entonces, el sistema operativo en el hipervisor, gracias a una optimización honesta, proporcionará cada vez menos tiempo de procesamiento. Este proceso se produce como una avalancha y salta furtivamente al cielo, aunque otras máquinas virtuales apenas lo noten. Y cuantos más núcleos, peor será la máquina afectada. En resumen, las máquinas virtuales muy cargadas y con muchos núcleos son las que más sufren.

Baja LA, pero hay robo.. Si LA es aproximadamente 0,7 (es decir, el hipervisor parece estar subcargado), pero se observa robo dentro de las máquinas virtuales individuales:

  • La opción con paravirtualización ya descrita anteriormente. La máquina virtual puede recibir métricas que indiquen robo, aunque el hipervisor está bien. Según los resultados de nuestros experimentos, esta opción de robo no supera el 10% y no debería tener un impacto significativo en el rendimiento de las aplicaciones dentro de la máquina virtual.
  • El parámetro LA se calcula incorrectamente. Más precisamente, en cada momento específico se calcula correctamente, pero cuando se promedia durante un minuto resulta que está subestimado. Por ejemplo, si una máquina virtual por cada tercio del hipervisor consume todos sus procesadores durante exactamente medio minuto, entonces LA por minuto en el hipervisor será 0,15; cuatro máquinas virtuales de este tipo funcionando simultáneamente darán 0,6. Y el hecho de que durante medio minuto en cada uno de ellos hubo un robo salvaje del 25% según el indicador de Los Ángeles ya no se puede descartar.
  • Nuevamente, debido al programador que decidió que alguien estaba comiendo demasiado y lo dejó esperar. Mientras tanto, cambiaré el contexto, manejaré las interrupciones y me ocuparé de otras cosas importantes del sistema. Como resultado, algunas máquinas virtuales no ven ningún problema, mientras que otras experimentan una degradación grave del rendimiento.

4. Otras distorsiones

Hay un millón de razones más para distorsionar el justo retorno del tiempo de procesamiento en una máquina virtual. Por ejemplo, hyperthreading y NUMA introducen dificultades en los cálculos. Confunden por completo la elección del núcleo para ejecutar el proceso, porque el programador utiliza coeficientes, pesos, que dificultan aún más el cálculo al cambiar de contexto.

Hay distorsiones debidas a tecnologías como el turbo boost o, por el contrario, el modo de ahorro de energía, que, al calcular el consumo, pueden aumentar o disminuir artificialmente la frecuencia o incluso el intervalo de tiempo en el servidor. Habilitar turbo boost reduce el rendimiento de un subproceso del procesador debido a un aumento en el rendimiento de otro. En este momento, la información sobre la frecuencia actual del procesador no se transmite a la máquina virtual y ésta cree que alguien le está robando el tiempo (por ejemplo, solicitó 2 GHz, pero recibió la mitad).

En general, puede haber muchas razones para la distorsión. Es posible que encuentre algo más en un sistema en particular. Es mejor comenzar con los libros a los que proporcioné enlaces arriba y recuperar estadísticas del hipervisor utilizando utilidades como perf, sysdig, systemtap, de las cuales decenas.

5. Conclusiones

  1. Es posible que se produzca cierta cantidad de robo debido a la paravirtualización y esto puede considerarse normal. Escriben en Internet que este valor puede ser del 5 al 10%. Depende de las aplicaciones dentro de la máquina virtual y de la carga que pone en sus dispositivos físicos. Aquí es importante prestar atención a cómo se sienten las aplicaciones dentro de las máquinas virtuales.
  2. La relación entre la carga en el hipervisor y el robo dentro de la máquina virtual no siempre está claramente interrelacionada; ambas estimaciones del robo pueden ser erróneas en situaciones específicas bajo diferentes cargas.
  3. El planificador tiene mala actitud hacia los procesos que exigen mucho. Intenta dar menos a quien pide más. Las grandes máquinas virtuales son malas.
  4. Un pequeño robo puede ser la norma incluso sin paravirtualización (teniendo en cuenta la carga dentro de la máquina virtual, las características de la carga de los vecinos, la distribución de la carga entre subprocesos y otros factores).
  5. Si desea descubrir el robo en un sistema específico, debe explorar varias opciones, recopilar métricas, analizarlas cuidadosamente y pensar en cómo distribuir uniformemente la carga. Son posibles desviaciones de cualquier caso, que deben confirmarse experimentalmente o examinarse en el depurador del núcleo.

Fuente: habr.com

Añadir un comentario