La Red de Conocimientos Pedagógicos - Currículum vitae - Optimización de la memoria de Rails

Optimización de la memoria de Rails

Sabemos que el uso de memoria de las aplicaciones Rails suele ser relativamente alto, especialmente el uso de memoria de las aplicaciones full-stack de alta resistencia está más cerca de 1G (por supuesto, esto también incluye el proceso Ruby que carga toda la aplicación Rails como sidekiq), por lo que normalmente adoptamos un enfoque más complicado para esta situación, usando un programa de monitoreo como puma_worker_killer para monitorear el proceso Rails y reiniciarlo después de que alcance un cierto uso de memoria. En otras palabras, el uso de memoria inicial de una aplicación suele estar entre 100 y 300 MB. A medida que pasa el tiempo, el proceso creará una gran cantidad de "objetos" y realizará la asignación y el reciclaje de memoria varias veces, por lo que la memoria seguirá aumentando. .

Después de conocer la situación básica, es hora de hablar sobre cómo optimizar el uso de memoria de Rails. Hay muchas soluciones. Aquí explicaremos la forma más fácil y rápida de implementar, que es comenzar. Comience con la asignación de memoria. Ruby usa malloc(3) de glibc para la asignación de memoria. Este es un asignador de memoria más antiguo con un rendimiento relativamente bajo y se generará una gran cantidad de fragmentos durante la asignación. Realmente, ahora hay muchos asignadores nuevos con excelente rendimiento que son compatibles con la API original y características probadas, como jemalloc y tmalloc. Aquí usamos jemalloc como asignador de memoria para aplicaciones Ruby. Se puede lograr el efecto.

Jemalloc es producido por Facebook. Se usó por primera vez como asignador de memoria en FreeBSD. Posteriormente, Firefox también comenzó a usarlo desde 3.0. Redis usa jemalloc de forma predeterminada en Linux desde 2.4 en adelante. Dado que tantos programas sensibles al rendimiento utilizan jemalloc, debe tener algo especial.

Lo especial de jemalloc es que combina las ventajas de otras tecnologías de asignación de memoria y utiliza asignación de memoria multinivel, caché de grupo de subprocesos y áreas de memoria divididas para reducir la contención de bloqueos entre subprocesos.

Estructura de jemalloc:

Asignación de memoria multinivel: jemalloc clasifica los objetos en tres categorías: objeto pequeño, objeto grande y objeto enorme según su tamaño.

Arena : jemalloc no divide la memoria y la administra en un área como malloc, sino que utiliza múltiples áreas de memoria pequeñas para administrarlas por separado. Cada bloque pequeño se llama "arena".

Caché de subprocesos en caché del grupo de subprocesos: tcache es el espacio de caché para asignar subprocesos. jemalloc usa tcache para reducir la competencia de bloqueo en la asignación de memoria de subprocesos, mejorando así la eficiencia de la asignación.

En este paso, veamos cuánta mejora se puede lograr aplicando Jemalloc a nuestro proceso Ruby.

Instalación

Elegimos probar en la versión 2.4.1. Además del método de instalación anterior, también puede instalar jemalloc-rb a través del paquete gem

Uso de memoria

Lo instalamos en uno de los dos servidores que ejecutan la misma aplicación. , mientras que el otro configurado como control no estaba instalado.

Aquí está el proceso con la brecha de rendimiento más obvia: el proceso sidekiq de la aplicación Rails

El proceso sidekiq en el servidor que no usa jemalloc

El servidor que usa jemalloc Puede ver que la brecha es muy obvia en el proceso sidekiq anterior. Por supuesto, no todos los procesos tienen tal efecto de optimización. Hablaremos de esto cuando resumamos.

De la comparación anterior y posterior de jemalloc anterior, podemos ver que la optimización de jemalloc todavía tiene efectos obvios. En cuanto a por qué la brecha entre sidekiq y puma era tan grande antes, esto lleva al hecho de que jemalloc solo optimiza y mejora el uso de la memoria y el rendimiento desde el nivel de asignación de memoria cuando su aplicación genera una gran cantidad de objetos y se ejecuta durante mucho tiempo. Con el tiempo, el efecto es más obvio, y si la aplicación en sí está relativamente simplificada y bien optimizada desde la perspectiva del programa, el mensaje de jemalloc no será obvio. Por lo tanto, jemalloc puede resolver su necesidad urgente de rendimiento de la memoria de la aplicación, pero desde una perspectiva sistémica, es mejor optimizar el rendimiento de la aplicación en sí.