...

Presión de memoria en el núcleo de Linux: repercusiones en los sistemas de alojamiento web

La presión de memoria en el núcleo de Linux afecta directamente a los sistemas de alojamiento: si la presión aumenta, el tiempo de CPU y las operaciones de E/S se desplazan hacia tareas más exigentes Reclaim, los tiempos de respuesta se alargan y aumentan los riesgos de OOM. Explico claramente cómo detecto, mido y mitigo la presión sobre la memoria, para que Alojamiento-Reaccionar de forma constante ante las cargas de trabajo.

Puntos centrales

Me centro en los factores clave que determinan el rendimiento y las interrupciones del servicio en los entornos de alojamiento web. Los siguientes puntos constituyen el hilo conductor en torno al cual oriento el diagnóstico y la optimización. Con esta visión general, evito interpretaciones erróneas de „RAM llena“ e identifico los verdaderos Presión a tiempo.

  • Métricas PSI Muestran los tiempos de espera en lugar de la mera ocupación y detectan los retrasos de forma temprana.
  • Carga de swap indica problemas de recuperación que agravan las operaciones de E/S y las latencias.
  • Límites de cgroups Controlar la limitación, la protección y el comportamiento en caso de OOM por servicio.
  • Desplazamiento de la caché Influye directamente en el rendimiento de la web y de las bases de datos.
  • Planificación de capacidades Y el ajuste mantiene el margen dinámico y evita el thrashing.

Así es como estructuro mis análisis, desde el núcleo hasta la aplicación, y aplico las medidas adecuadas por orden de prioridad. La atención se centra en los resultados medibles efectos, no al trabajo a destajo.

¿Qué significa «Memory Pressure» en el núcleo de Linux?

La „carga de memoria“ significa que el núcleo dedica un tiempo apreciable a liberar memoria, en lugar de continuar con el trabajo de los procesos de usuario; la CPU dedica entonces más recursos a operaciones de lectura, escritura y expulsión, mientras las solicitudes quedan en espera. Distingo claramente entre „RAM llena» y «falta de memoria utilizable» Espacio libre“: Una caché „llena“ es saludable; los cuellos de botella solo se producen cuando aumentan las inversiones en recuperación. El núcleo analiza las listas inactivas y escribe sucio-Elimina páginas, borra la caché de archivos y traslada las páginas anónimas a la memoria externa en cuanto se superan los umbrales de Watermarks. El tiempo dedicado a estas actividades es decisivo; se refleja en las fases de espera de las tareas y en el aumento de los tiempos de respuesta. Un servidor puede funcionar de forma fluida con una utilización del 95 % según el modelo %, siempre que la caché se pueda recuperar fácilmente, pero puede ralentizarse considerablemente con una baja carga de trabajo si es necesario desplazar páginas anónimas activas.

Comprender y medir el PSI

La información sobre el estancamiento por presión (PSI) permite visualizar la presión de la memoria, ya que no mido la ocupación, sino los retrasos. En /proc/presión/memoria Veo „some“ y „full“: „some“ describe los momentos en los que al menos una tarea está a la espera de memoria, mientras que „full“ indica las fases en las que todas están atascadas. Ejemplo: „some avg10=4,67“ significa que, en los últimos 10 segundos, se produjeron 4,67 % de tiempo de paradas debido a cuellos de botella en la memoria; „full avg10=0,30“ indica paradas completas poco frecuentes. Correlaciono los valores crecientes de „some“ con los tiempos de respuesta en una fase temprana y escalo, ajusto o aligero la carga antes de que aparezcan errores graves de OOM. Esta perspectiva evita que me deje engañar por una RAM aparentemente „libre“, ya que las páginas libres sin acceso rápido Reclaim-Aprovechan poco esa oportunidad.

Variable medida Valor orientativo Síntoma Acción
Memoria PSI (promedio 10) > 2–3 % de forma continuada Aumentan los tiempos de respuesta Comprobar el margen de RAM, ajustar con precisión los límites de los cgroups
Memoria PSI llena (avg10) > 0,1 % perceptible Tiempos de inactividad breves Identificar la causa, poner fin al thrashing
MemAvailable < 10 % de la RAM Margen reducido Aliviar la carga de la caché y la carga de trabajo, planificar la capacidad
vmstat si/so permanente > 0 Presión de intercambio Ajustar Swappiness/Swap, proteger Hotset

Síntomas en entornos de alojamiento web

En servidores muy activos, lo primero que observo son picos de latencia, mientras que la carga de la CPU parece mantenerse moderada; el kernel se encuentra en bucles de recuperación, las operaciones de E/S se acumulan y las solicitudes quedan en espera. La media de carga sube, aunque los núcleos parecen estar libres, porque muchas tareas se bloquean en la memoria o en las E/S; este es un indicio clave de un aumento de Impresiones. Los valores persistentes de «si/so» en vmstat indican que el sistema está realizando operaciones de intercambio de memoria de forma activa, lo que ralentiza los handshakes de TLS, los contenidos dinámicos y las rutas de consulta. Si no se soluciona, el sistema entra en «thrashing»: la CPU dedica la mayor parte del tiempo a la paginación y al intercambio de memoria, en lugar de realizar tareas útiles. En una situación de escalada, el «OOM-Killer» interviene y termina los procesos con una puntuación elevada; una medida específica Análisis del OOM-Killer Me ayuda a detectar patrones y errores de configuración.

Importancia para las cargas de trabajo de alojamiento y los cgroups

En entornos compartidos, basta con unas pocas aplicaciones que consuman muchos recursos de memoria para aumentar las latencias de muchos clientes; los cgroups mitigan los efectos, pero no solucionan el problema de un dimensionamiento incorrecto Instancias. En los VPS y las instancias en la nube, una memoria RAM escasa o una estrategia de intercambio deficiente provocan picos de carga más rápidamente; el aislamiento protege a los demás, pero no al propio servicio. Las bases de datos dependen de grandes grupos de búferes; si Reclaim los desplaza o interviene el intercambio, los tiempos de consulta aumentan y el rendimiento se reduce significativamente. Las orquestaciones de contenedores utilizan memory.low, memory.high y memory.max para proteger servicios importantes, mitigar los bloqueos y, en caso de emergencia, terminarlos de forma selectiva. Por eso elijo los límites de forma consciente y superviso el PSI por servicio, para poder tomar medidas correctivas a tiempo y reservar recursos para los servicios críticos Cargas de trabajo mantenerlo despejado.

Estrategia de seguimiento y métricas

Consulto los valores de MemAvailable, Buffers y Cached para entender cuánta memoria se puede recuperar a corto plazo; los valores de MemFree por sí solos pueden llevar fácilmente a conclusiones erróneas. Al mismo tiempo, consulto vmstat: unos valores de si/so persistentes indican presión de swap, lo que dispara enormemente la E/S y aumenta las latencias; para más información sobre Utilización de swaps Utilizo patrones de diagnóstico contrastados. PSI me proporciona el elemento que me faltaba, ya que „some“ y „full“ cuantifican los retrasos reales; activo alertas cuando se superan los umbrales y distingo los picos de carga de los cuellos de botella crónicos. Las series temporales obtenidas a través de sar o de la pila de observabilidad hacen visibles los patrones y me ayudan a confirmar los resultados del ajuste. dmesg revela eventos OOM que indican límites estrictos o configuraciones erróneas; así construyo una imagen coherente desde la perspectiva del kernel, el comportamiento de E/S y Aplicación.

Cargas de trabajo típicas bajo presión

Los servidores web como Nginx o Apache sirven el contenido más lentamente cuando Reclaim y Swap se ejecutan en segundo plano; las conexiones Keep-Alive permanecen abiertas durante más tiempo, lo que agrava las colas. Las pilas de PHP y Python ocupan memoria RAM debido a las cachés de los frameworks, las partes JIT y los datos de sesión; en caso de desplazamiento, estos datos oscilan entre la RAM y el almacenamiento y alargan considerablemente los tiempos de respuesta. Las bases de datos pierden velocidad en cuanto los grupos de búferes se reducen o parte de su contenido acaba en el swap; incluso una latencia adicional mínima por operación de E/S se acumula cuando hay muchas Consultas. Los servicios de almacenamiento en caché, como Redis o Memcached, necesitan que las operaciones se realicen en la memoria RAM; si las áreas de claves acaban en el espacio de intercambio, la ventaja se pierde y aumenta el riesgo de que se interrumpan en momentos de mayor carga. En todos los casos, las métricas de PSI y del espacio de intercambio ofrecen las indicaciones más claras de que la memoria se ha convertido en un cuello de botella, y no las CPU.

Optimización del sistema y parámetros del núcleo

Empiezo por vm.swappiness: un ajuste moderadamente reducido evita un uso excesivo del swap sin bloquear la recuperación necesaria; mido los efectos de forma sistemática con PSI. A continuación, optimizo vm.dirty_ratio y los límites relacionados, para no provocar largas oleadas de vaciado y, al mismo tiempo, no generar un exceso de operaciones de escritura menores; ambas cosas tienen un efecto notable Efectos en cuanto a latencias. En Cgroups v2 configuro «memory.low» para servicios críticos, «memory.high» para la limitación en caso de sobrecarga y «memory.max» como límite estricto con OOM controlables. Presto especial atención a las topologías NUMA: puede producirse presión local aunque aún quede RAM libre a nivel global; la vinculación de procesos y memoria mitiga este tipo de trampas. Por último, compruebo el comportamiento de la caché de páginas; el desplazamiento innecesario reduce las tasas de acierto y supone una pérdida de tiempo inmediata en cargas de trabajo web y de bases de datos, a lo que se suma la Optimización de la caché de páginas ofrece información útil.

Análisis en profundidad de las rutas de Reclaim

Para elegir las medidas adecuadas, distingo entre: kswapd y Recuperación directa. kswapd funciona de forma asíncrona cuando se caen por debajo de los umbrales; es relativamente suave siempre que haya suficiente caché fácilmente recuperable. Direct Reclaim interviene de forma síncrona en los contextos de ejecución cuando los hilos necesitan páginas de forma urgente; es aquí donde se producen los atascos perceptibles para los usuarios. Observo si la recuperación afecta más a la caché de archivos o a las páginas anónimas: si el núcleo desplaza principalmente la caché de archivos, aumentan las faltas de caché; si desplaza la memoria anónima (p. ej., el montón), existe el riesgo de paradas bruscas y actividad de intercambio. Los mecanismos modernos de conjunto de trabajo tienen en cuenta las distancias de re-fallo para mantener las páginas útiles durante más tiempo; si, a pesar de ello, observo muchos re-fallos repetidos, sé que los conjuntos activos son mayores que el espacio disponible Espacio libre se han convertido en.

Además, tengo en cuenta la compactación y la desfragmentación: kcompactd intenta crear áreas contiguas, por ejemplo, para grandes asignaciones o THP. Si la compactación se retrasa, observo un mayor consumo de CPU en kcompactd, latencias crecientes y un aumento de los valores „full“ de PSI en los picos de carga. En estos casos, suele ser más sensato reducir la carga o ajustar las políticas de THP, en lugar de limitarse a „aumentar el swap“.

Estrategias de swap en detalle

El swap no es un enemigo, sino una herramienta; sin embargo, si se utiliza incorrectamente, puede aumentar la latencia. Distingo entre:

  • Sin swap: A salvo frente a los retrasos en el intercambio, pero arriesgado en los picos: los OOM se producen antes y Reclaim no dispone de un margen de seguridad.
  • Swap moderado En un SSD rápido: ideal para almacenar páginas anónimas inactivas; protege los conjuntos activos en la RAM si los parámetros de swappiness y los límites de cgroup se configuran adecuadamente.
  • zswap/zram: La compresión alivia la carga de E/S; es adecuada para hosts con poca actividad de E/S o como amortiguador frente a picos de carga momentáneos. Compruebo la capacidad de la CPU y la tasa de compresión para evitar que la CPU se vea ralentizada.

No configuro el valor de swappiness en un nivel bajo de forma generalizada; en cargas de trabajo con una caché de archivos grande, conviene establecer un valor de swappiness algo más alto para descartar páginas anónimas inactivas y mantener estable la caché de archivos. Protejo los servicios críticos (por ejemplo, las bases de datos) con «memory.low» y, si es necesario, bloqueando sus conjuntos activos en la RAM, para que el intercambio no afecte a lo que no debe. Lo fundamental es que vmstat si/so y el PSI descienda de forma constante cuando ajuste la estrategia; de lo contrario, haré los ajustes necesarios.

THP, compactación y fragmentación

Páginas transparentes enormes (THP) Ahorran accesos a la TLB y ayudan a las aplicaciones que suponen una gran carga para la CPU y consumen mucha memoria. Sin embargo, bajo presión, provocan trabajo de compactación; en ese caso, la opción „always“ puede provocar grandes atascos. Utilizo „madvise“ de forma selectiva para cargas de trabajo que se benefician de ello (por ejemplo, determinados motores en memoria) y, en el caso de las pilas web sensibles a la latencia, prefiero desactivar THP de forma selectiva o habilitarlo únicamente mediante madvise. Además, observo vm.compaction_proactiveness y comprueba si la compactación proactiva retrasa la formación de estercol o si realmente la reduce. Si las páginas de THP se fragmentan con frecuencia o la compactación se acelera demasiado, eso indica que hay muy poco Espacio libre o patrones de asignación inadecuados en la aplicación.

Trampas NUMA e impresión local

En los hosts NUMA, la „RAM libre“ global es engañosa: un socket puede estar saturado, mientras que otro permanece sin utilizar. Compruebo las estadísticas NUMA y anclo los procesos localmente (vinculación de CPU/memoria) para que los conjuntos activos permanezcan cerca de la carga de cálculo. La recuperación directa en un nodo, a pesar de las reservas globales, indica desequilibrios NUMA; en estos casos, resultan útiles las asignaciones intercaladas para servicios muy dispersos o la vinculación estricta para cargas de trabajo monolíticas. El PSI por cgroup, combinado con las estadísticas NUMA, me indica si un único nodo es el responsable de generar las colas.

Medidas relacionadas con la aplicación

Analizo los perfiles de memoria con ps, top, htop y herramientas de perfilado para detectar los verdaderos devoradores de memoria y las fugas; al hacerlo, presto atención a cómo evolucionan los hotsets a lo largo del tiempo. Elijo las cachés de las aplicaciones de forma deliberada: si son demasiado grandes, generan presión; si son demasiado pequeñas, se sacrifica la velocidad; realizo los ajustes basándome en el PSI y los tiempos de respuesta, no en corazonadas. Ante señales de presión detectadas, la aplicación puede liberar voluntariamente cachés menos críticas o datos temporales; de este modo, reduzco los bloqueos sin tener que modificar los límites globales. Ajusto los parámetros de inicio y la configuración del GC (por ejemplo, para las JVM) de manera que los conjuntos de trabajo se mantengan correctamente en la RAM; mitigo los patrones de asignación agresivos mediante el procesamiento por lotes. También vigilo los artefactos de compilación y los símbolos de depuración, ya que los restos que se pasan por alto suponen un coste oculto Memoria y aumentan el riesgo de que se produzcan paradas posteriores.

Matices de cgroups v2 y estrategias OOM

Con Cgroups v2 separo claramente la protección, la limitación y los límites estrictos: memoria.baja Reserva margen de capacidad para los servicios críticos; el resto se destina a grupos menos importantes. memoria.alta Cuando se supera el límite, reduce el rendimiento de forma selectiva y obliga a las aplicaciones a liberar memoria antes de que el sistema se vea afectado. memoria.max Es la última línea de defensa: si se supera, se produce un OOM en un entorno controlado. Configuro PSI por cada cgroup, para que las alertas se activen allí donde se producen los bloqueos; el PSI global se mantiene estable mientras un único servicio se colapsa —y es precisamente este patrón el que quiero detectar—. Junto con las prioridades OOM, establezco reglas de sacrificio claras: los trabajadores por lotes sin importancia se cierran primero, mientras que las API del núcleo conservan su Espacio libre.

Virtualización: «ballooning», KSM y «overcommit»

En entornos virtualizados me enfrento a una doble presión: el sistema invitado parece detectar memoria RAM libre, mientras que el hipervisor, a través de Vuelo en globo . Esta jugada aumenta los costes de recuperación para ambas partes. Mido el PSI en el invitado y lo correlaciono con las métricas del hipervisor; si el PSI aumenta durante los eventos de «ballooning», la máquina virtual necesita más capacidad garantizada o mejores políticas de Cgroup en el host. KSM Ahorra memoria RAM gracias a la deduplicación de páginas idénticas, pero consume recursos de la CPU; en entornos de alojamiento con muchas máquinas virtuales similares, puede merecer la pena siempre que la carga adicional de la CPU no ponga en riesgo los SLO. Solo planeo el overcommit (por ejemplo, la asignación agresiva de muchas máquinas virtuales pequeñas) con reservas fijas de SLO y una estricta memoria.baja para sistemas en los que la latencia es un factor crítico.

Decisiones de arquitectura en el alojamiento web

Apuesto por la distribución horizontal para que las instancias individuales sufran menos picos de carga; los grupos escalables amortiguan los picos extremos y mantienen las latencias más bajas. Separo claramente las funciones: las bases de datos, la aplicación y el almacenamiento en caché cuentan con sus propios grupos de recursos, para que los procesos de recuperación no generen efectos secundarios inesperados más allá de los límites del sistema. Elijo el almacenamiento teniendo en cuenta la latencia de escritura, ya que los vaciados de páginas sucias repercuten directamente en los tiempos de respuesta; una ruta rápida reduce notablemente los tiempos de recuperación. En los clústeres, preveo reservas de RAM por nodo y las controlo mediante políticas de programador, para que la carga y el consumo de memoria se distribuyan de forma más uniforme. Automatizo el escalado con umbrales PSI, de modo que el aumento de los valores „some“ desencadene acciones antes de que se produzcan frenadas bruscas y Matar-suceden.

Planificación de la capacidad y modelos de margen de capacidad

Defino el margen de seguridad de forma cuantificable: mantengo reservas suficientes para que el „some“ PSI se mantenga por debajo de los umbrales definidos en picos normales y para que el „full“ prácticamente no se produzca. Para ello utilizo percentiles (por ejemplo, el percentil 99 de la carga horaria) y preveo entre 10 y 30 % de RAM adicional, dependiendo de la volatilidad de la carga de trabajo. Las bases de datos reciben reservas fijas más grandes, mientras que las interfaces web se escalan de forma más dinámica. Calibro los tiempos de recuperación: ¿a qué velocidad descienden el PSI y el si/so tras un pico? Si se mantienen elevados, es señal de que las reservas son insuficientes o de que la estrategia de intercambio/datos sucios no es adecuada. De este modo, la planificación de la capacidad se convierte en un proceso continuo en lugar de una estimación anual.

Avisos y ajuste controlado por SLO

Vinculo PSI con los SLO de los usuarios: si „some avg10“ aumenta al mismo tiempo que las latencias de la API, intervengo. Clasifico las alertas en „amarillo“ (2-3 % „some“ continuos, „full“ cercano a 0) y „rojo“ (más de 5 % „some“ o „full“ > 0,1 %). Las alertas basadas en cgroups ayudan a aislar a la minoría ruidosa. Además, configuro alertas ante el aumento de las colas sucias y los tiempos de espera de escritura, para poder suavizar las oleadas de datos sucios a tiempo. El objetivo es que las medidas de ajuste (swappiness, memory.high, tamaños de caché) sean observables y reversibles; implemento los cambios de forma gradual y comparo los resultados antes y después utilizando las mismas métricas.

Diagnóstico paso a paso en el día a día

Primero compruebo „free -h“ y „MemAvailable“: si el valor desciende notablemente, busco cachés que se puedan liberar de forma razonable y servicios con «hotsets» crecientes. A continuación, ejecuto «vmstat» a intervalos cortos para detectar tendencias, por si acaso; el intercambio persistente confirma la presión y me lleva a la ruta de E/S. A continuación, leo /proc/pressure/memory y evalúo los valores «some» y «full» a lo largo de 10, 60 y 300 segundos; relaciono directamente los valores medios crecientes con las latencias observadas. dmesg me muestra rastros de OOM y revela qué procesos han provocado o sufrido crisis de memoria recientemente; a partir de ahí deduzco los límites y las prioridades para los cgroups. A partir de todo ello, formulo una hipótesis, aplico pequeños ajustes, verifico con PSI y mantengo la Tiempo de respuesta de un vistazo.

Manuales de procedimientos y cadenas de causas típicas

Hay algunos patrones que se repiten una y otra vez:

  • Las tareas de copia de seguridad o de escaneo desplazan la caché de páginas: De repente, bajan las tasas de aciertos de la caché y la web y la base de datos se ralentizan. Medida: reducir la carga de los trabajos (prioridad de E/S), desplazar las franjas horarias, establecer «memory.high» para el cgroup de los trabajos y proteger el presupuesto de la caché de páginas de los servicios críticos.
  • Fugas en los procesos de los trabajadores: Aumento gradual de la memoria anónima; el PSI „some“ va subiendo a lo largo de varias horas. Medida: identificar la fuga, implantar políticas de reinicio automático y reciclaje, y establecer límites de memoria para que las fugas no pongan en peligro todo el host.
  • Estancamientos debidos al THP: La carga de kcompactd aumenta durante los picos de tráfico. Medida: configurar THP en „madvise“, ajustar los servicios afectados, comprobar los parámetros de compactación y aumentar el margen de capacidad.
  • Impresión local NUMA: Un socket se satura, aunque hay memoria RAM libre a nivel global. Medida: corregir las afinidades, aplicar el interleave para cargas de trabajo muy dispersas y ajustar el reparto de carga en el programador.
  • Memoria virtual en discos lentos: si/so aumenta, los tiempos de respuesta se disparan. Medida: trasladar el swap a un almacenamiento más rápido, evaluar zswap/zram, ajustar el valor de swappiness y las políticas de cgroup.

Cada runbook termina con una validación: ¿se producen „some/full“ y se estabilizan las latencias? Si no es así, la hipótesis era errónea o incompleta, por lo que sigo iterando.

Herramientas y trazado en la empresa

Además de las herramientas clásicas, apuesto por un análisis más detallado: observo las relaciones entre la caché de páginas y los datos anónimos, las tasas de fallos de página, los patrones de re-fallos y las colas de reescritura. Los enfoques basados en eBPF y el rastreo me indican con precisión dónde se producen los tiempos de espera, por ejemplo, a lo largo de las rutas de recuperación, en la reescritura o en la asignación de bloques grandes. Para mí es importante contar con una instrumentación eficiente y apta para producción: ventanas de activación cortas, muestreo en lugar de registro continuo y una correlación clara con las métricas de la aplicación. Así puedo identificar las causas antes de realizar ajustes generalizados en los parámetros.

Puntos clave y próximos pasos

La «presión de memoria» describe el tiempo perdido debido a la escasez de memoria, no solo a la RAM ocupada; la mido con PSI, detecto las tendencias con antelación y actúo basándome en los datos. Quien analice conjuntamente MemAvailable, vmstat (tanto en modo si como en modo so), PSI y dmesg, descubrirá las verdaderas causas de los picos de latencia y el thrashing. Mediante el ajuste de los parámetros de swappiness, dirty y cgroup, reduzco los bloqueos de forma selectiva y garantizo a los servicios importantes su Espacio libre. A nivel de arquitectura, la distribución horizontal, la clara división de funciones y las rutas de almacenamiento rápidas mitigan las consecuencias de cualquier pico de carga. Al final, lo que cuenta es que vincule continuamente el diagnóstico y las medidas correctivas: medir, ajustar, volver a medir… hasta que el rendimiento y Estabilidad volver a encajar.

Artículos de actualidad

Rack de servidores con sistemas Linux y visualización del uso de la memoria
Servidores y máquinas virtuales

Entender el OOM Killer: cuando Linux termina procesos

Descubre cómo funciona el OOM Killer en Linux cuando hay falta de memoria, cómo termina los procesos y cómo, como administrador en entornos de alojamiento web, puedes evitar los problemas de falta de memoria utilizando la palabra clave «oom killer linux».

Un administrador analiza los registros de «journalctl» en un servidor Linux del centro de datos
Administración

Uso eficaz de `journalctl`: análisis de errores en servidores Linux

Aprende a utilizar `journalctl` para analizar de forma eficaz los errores en servidores Linux. Con filtros de fecha y hora, servicio y prioridad, podrás analizar los registros de Linux de forma estructurada y optimizar la resolución de problemas en tus servidores.