¿Qué debo hacer si el contenedor consume recursos de memoria? ¡Resolvamos este problema!

1. El mecanismo y las características de la gestión de memoria de Linux

Asesino OOM

  1. OOM Killer eliminará un proceso en ejecución para liberar algo de memoria si la memoria es insuficiente en el sistema Linux. Si el proceso es el punto de entrada del contenedor, el contenedor sale. docker inspect El comando mira el contenedor, el contenedor está en el estado "salido" y "OOMKilled" es verdadero.
  2. Todos los programas en Linux llaman a malloc() para solicitar memoria. Si la memoria es insuficiente, simplemente devuelve un error desde malloc(). ¿Por qué matar el proceso en ejecución? Linux permite que los procesos soliciten memoria que supere el límite de memoria física real. Debido a que malloc() se aplica a la dirección virtual de la memoria, el sistema solo le da al programa un rango de direcciones.Como no se escriben datos, el programa no obtiene la memoria física real. La memoria física solo se asignará al programa cuando el programa realmente escriba datos en esta dirección. PD: la memoria virtual  ps auxse ve a través de VSZ; la memoria física  ps auxRES (también conocida como RSS) se ve
  3. Cuando ocurre OOM, ¿qué criterios usa Linux para seleccionar el proceso que se va a eliminar? Esto es para mencionar que hay una función oom_badness() en el kernel de Linux, que define los criterios para seleccionar procesos.
  4. ¿Cómo podemos determinar rápidamente que el contenedor tiene OOM? Esto se puede encontrar a tiempo mirando el registro del kernel. Use  journalctl -k el comando o vea el archivo de registro directamente /var/log/message

Grupo C de memoria

/sys/fs/cgroup/memory

  1. memory.limit_in_bytes, la cantidad máxima de memoria disponible para todos los procesos en un grupo de control
  2. memory.oom_control, cuando el uso de memoria del proceso en el grupo de control alcanza el límite superior, este parámetro puede determinar si se activará OOM Killer (el valor predeterminado es), por supuesto, solo se puede eliminar el proceso en el grupo de control. echo 1 > memory.oom_control Incluso si la memoria utilizada por todos los procesos del grupo de control alcanza el límite superior establecido por memory.limit_in_bytes, el grupo de control no eliminará los procesos internos, pero afectará a los procesos del grupo de control que solicitan páginas de memoria física. Estos procesos estarán detenidos y no podrán ejecutarse.
  3. memory.usage_in_bytes, de solo lectura, es la memoria total utilizada realmente por todos los procesos en el grupo de control actual.

Tipo de memoria Linux 

  1. El kernel necesita asignar memoria a la tabla de páginas, la pila del kernel y la losa, que es el conjunto de caché de varias estructuras de datos del kernel;
  2. Memoria de proceso de modo de usuario
    1. La memoria RSS incluye la memoria del segmento de código del proceso, la memoria de la pila, la memoria del montón y la memoria de la biblioteca compartida.
    2. Caché de página para leer y escribir archivos. Es un mecanismo para utilizar la memoria física libre para mejorar el rendimiento de lectura y escritura de archivos de disco , ya que el comportamiento predeterminado de las llamadas al sistema read() y write() almacenará las páginas leídas o escritas en la caché de páginas.
  3. La gestión de memoria de Linux tiene un mecanismo de recuperación de página de memoria (recuperación de marco de página), que decidirá si se inicia la recuperación de memoria en función de si la memoria física libre en el sistema es inferior a un determinado umbral (wartermark). El algoritmo de recuperación de memoria determinará qué páginas de memoria se liberan primero según los diferentes tipos de memoria y el principio de memoria usado menos recientemente, que es el algoritmo LRU (Usado menos recientemente). Debido a que las páginas de memoria de Page Cache solo sirven como caché, naturalmente se liberarán primero.

Memoria Cgroup no limita la memoria del kernel (como tablas de páginas, losas, etc.). Solo se restringen dos tipos de memoria relacionados con el modo de usuario, RSS (Tamaño de conjunto residente) y Caché de página. Cuando el proceso en el grupo de control necesita solicitar nueva memoria física, y el valor en memory.usage_in_bytes excede el valor del límite superior de memoria memory.limit_in_bytes en el grupo de control, entonces la recuperación de memoria de Linux (reclamación de marco de página) que mencionamos anteriormente es invocado. Luego, parte de la memoria caché de la página en este grupo de control se liberará de acuerdo con el tamaño de la memoria recién aplicada, de modo que aún podamos solicitar con éxito la nueva memoria física, y la sobrecarga total de la memoria física memory.usage_in_bytes en todo el grupo de control no lo hará. supere el valor límite anterior memory.limit_in_bytes. PD: Entonces habrá un fenómeno en el que el uso de la memoria del contenedor siempre estará en un punto crítico.

Hay un parámetro memory.stat en Memory Cgroup, que puede mostrar el costo real de varios tipos de memoria en el grupo de control actual. No podemos usar memory.usage_in_bytes en Memory Cgroup, pero necesitamos usar el valor rss en memory.stat. Esto es muy similar a cómo usamos el comando libre para verificar la memoria disponible de un nodo. En lugar de mirar el valor debajo del campo "libre", debemos mirar el valor debajo del campo "disponible" después de eliminar la página. Cache.

intercambio

El intercambio es una porción de espacio en disco. Cuando la memoria está llena, puede escribir temporalmente datos que no se usan comúnmente en la memoria en este espacio de intercambio. De esta forma, el espacio de la memoria se puede liberar para satisfacer las necesidades de las nuevas aplicaciones de memoria.

  1. Abra el espacio de intercambio en el nodo host y el intercambio se puede usar en el contenedor.
    1. Debido al espacio de intercambio, el contenedor que habría sido eliminado por OOM puede funcionar bien (no se excede el RSS). Si un programa en un contenedor tiene una pérdida de memoria (pérdida de memoria), entonces Memory Cgroup puede eliminar el proceso a tiempo para que no afecte a otras aplicaciones en todo el nodo. Como resultado, el proceso de pérdida de memoria no se elimina y continúa leyendo y escribiendo en el disco de intercambio, lo que afecta el rendimiento de todo el nodo.
    2. Cuando la memoria es escasa, ¿cómo decide el sistema Linux si liberar primero la memoria caché de página o liberar y escribir primero la memoria anónima en el espacio de intercambio? Si el sistema libera todo el caché de página primero, una vez que haya operaciones frecuentes de lectura y escritura de archivos en el nodo, el rendimiento del sistema disminuirá. Si el sistema Linux primero libera la memoria anónima y la escribe en Swap, entonces, una vez que la memoria anónima liberada debe usarse de inmediato, debe volver a leerse desde el espacio de intercambio a la memoria, lo que hará que el intercambio (de hecho, disk) leer Las escrituras frecuentes conducen a la degradación del rendimiento del sistema.
  2. Obviamente, cuando liberamos memoria, necesitamos equilibrar la liberación de Page Cache y la liberación de memoria anónima . La función del valor del parámetro swappiness de Linux es que después de que el sistema tenga espacio de intercambio, cuando el sistema necesite recuperar memoria, ya sea para liberar primero la memoria en la memoria caché de la página o para liberar primero la memoria anónima (es decir, escribir en el intercambio) .
  3. También hay un intercambio de memoria en cada grupo de control de Memory Cgroup. La diferencia es que cuando el valor del parámetro swappiness en cada grupo de control de Memory Cgroup es 0, la memoria en el grupo de control puede dejar de escribir en Swap.

2. Problemas y soluciones de la gestión de memoria Linux

Dado que el principio del kernel de Linux es usar la memoria tanto como sea posible en lugar de reclamarla continuamente, cuando el proceso en el contenedor solicita memoria, el uso de la memoria a menudo seguirá aumentando. Cuando el uso de memoria del contenedor está cerca del límite, se activará la recuperación de memoria directa a nivel del contenedor (reclamación directa) para recuperar páginas de archivo limpias. Este proceso ocurre en el contexto del proceso de solicitud de memoria, por lo que provocará la aplicación en el contenedor se congele; si la memoria La tasa de aplicación es alta, lo que también puede causar que el contenedor OOM (memoria insuficiente) se elimine, lo que hace que la aplicación en el contenedor se interrumpa y reinicie.

Cuando los recursos de memoria de toda la máquina son escasos, el kernel activará el reciclaje de acuerdo con el nivel de agua de la memoria libre (la parte libre de las estadísticas de la interfaz del kernel): cuando el nivel de agua alcance el nivel de agua bajo, el reciclaje de la memoria de fondo se activará, y el proceso de reciclaje se completará con el subproceso del kernel kswapd sin bloquear El proceso de la aplicación se está ejecutando y admite la recuperación de páginas sucias; cuando el nivel de agua libre alcance el nivel de agua mínimo (Min < Low), se activará global recuperación de memoria directa Este proceso ocurre en el contexto de la asignación de memoria por parte del proceso y busca actualizaciones en varias páginas, por lo que el rendimiento se ve muy afectado y todos los contenedores en el nodo pueden verse afectados. Cuando la tasa de asignación de memoria de toda la máquina supera y reclama la tasa, se activará un rango más amplio de OOM, lo que resultará en una disminución en la disponibilidad de recursos.

cuestión de equidad

Los contenedores con uso excesivo de recursos (Uso > Solicitud) pueden competir por recursos de memoria con contenedores que no se usan en exceso: Para el nivel de Solicitud, Kubelet establece la interfaz cgroups cpu.shares de acuerdo con la Solicitud de CPU como el peso relativo de la competencia por los recursos de CPU entre Contenedores Cuando los recursos son escasos, la proporción de tiempo de CPU compartido entre contenedores se dividirá de acuerdo con la relación de Solicitud para cumplir con la equidad, mientras que la Solicitud de memoria no establece la interfaz de cgroups de forma predeterminada, que se utiliza principalmente para la programación y la referencia de desalojo. Cuando el recurso de memoria del nodo es escaso, dado que la solicitud de memoria no está asignada a la interfaz de cgroups, la memoria disponible entre los contenedores no se dividirá de acuerdo con la proporción de solicitudes como la CPU, por lo que hay una falta de garantía de equidad de recursos.

Kubelet proporciona la función MemoryQoS en Kubernetes 1.22 y superior, y garantiza aún más la calidad de los recursos de memoria del contenedor a través de la capacidad memcg QoS proporcionada por Linux cgroups v2, que incluye:

  1. Establezca la solicitud de memoria del contenedor en la interfaz cgroups v2 memory.min, y la memoria global no reclamará la memoria solicitada por el bloqueo.
  2. En función del límite de memoria basado en contenedores, configure la interfaz de cgroups v2 memory.high, y cuando la memoria del pod esté sobreutilizada (Memory Usage > Request), el límite actual se activa primero para evitar OOM causado por una cantidad ilimitada de memoria sobreutilizada.

Sin embargo, desde la perspectiva de los usuarios que utilizan los recursos, todavía existen algunas deficiencias:

  1. Cuando la solicitud de declaración de memoria del pod = límite, aún puede haber restricciones de recursos en el contenedor, y la recuperación de memoria directa desencadenada en el nivel de memcg puede afectar el RT (tiempo de respuesta) del servicio de la aplicación.
  2. Actualmente, la solución no considera la compatibilidad con cgroups v1, y el problema de equidad de los recursos de memoria en cgroups v1 aún no se ha resuelto.

Capacidad garantizada (bloqueada) para el uso de memoria durante la recuperación de memoria

En un clúster de Kubernetes, puede ser necesario garantizar la prioridad entre Pods. Por ejemplo, los pods de alta prioridad necesitan una mejor estabilidad de los recursos.Cuando los recursos generales de la máquina son escasos, es necesario evitar el impacto en los pods de alta prioridad tanto como sea posible. Sin embargo, en algunos escenarios reales, los pods de baja prioridad a menudo ejecutan tareas que consumen recursos, lo que significa que es más probable que causen una amplia gama de restricciones de recursos de memoria, interfieran con la calidad de los recursos de los pods de alta prioridad y sean reales. "alborotadores" ". En este sentido, actualmente Kubernetes expulsa principalmente los Pods de baja prioridad a través de Kubelet, pero el tiempo de respuesta puede ocurrir después del reciclaje de la memoria global.

Alibaba Cloud Container Service ACK se basa en el subsistema de memoria mejorado de Alibaba Cloud Linux 2. Los usuarios pueden usar la función QoS de memoria de contenedor más completa por adelantado en cgroups v1, de la siguiente manera:

  1. Garantice la imparcialidad de la recuperación de memoria entre los Pods. Cuando los recursos de memoria de toda la máquina son escasos, la memoria se recupera primero de los Pods con uso excesivo de memoria (Uso > Solicitud) (Memory QoS admite la configuración de una marca de agua para la recuperación de memoria activa para dichos Pods, y memoria El uso está limitado cerca del nivel del agua), y los spoilers están restringidos para evitar la disminución de la calidad de los recursos de toda la máquina.
  2. Cuando el uso de la memoria del Pod esté cerca del límite, una parte de la memoria se recuperará de forma asincrónica en segundo plano en primer lugar para aliviar el impacto en el rendimiento causado por la recuperación directa de la memoria.
  3. Cuando el recurso de memoria del nodo es escaso, se da prioridad a la calidad de funcionamiento de la memoria del pod garantizado/ampliable. La función QoS de memoria permite la clasificación del nivel de agua mínimo global y la QoS de memcg del núcleo. Cuando los recursos de memoria de toda la máquina son escasos, la memoria se recupera primero del contenedor BE, lo que reduce el impacto de la recuperación de memoria global en el contenedor LS; también admite la recuperación prioritaria de los recursos de memoria utilizados en exceso para garantizar la equidad de los recursos de memoria.

Supongo que te gusta

Origin blog.csdn.net/m0_37723088/article/details/130576961
Recomendado
Clasificación