Gestión y rendimiento de la memoria

julio 16

En Raima siempre nos esforzamos por aumentar el rendimiento de nuestros productos. Recientemente trabajé con uno de nuestros clientes para resolver un problema relacionado con el rendimiento de la base de datos y descubrí algunos datos interesantes. La solución a un problema de rendimiento de la base de datos puede requerir algo más que agregar memoria adicional que se ejecuta a velocidades más altas.

Métodos de optimización

En la gestión de datos existen innumerables formas de optimizar las diferentes operaciones involucradas en el almacenamiento y recuperación de datos. Muchas veces, las optimizaciones en un área pueden requerir compensaciones en otras. Un ejemplo común de esto es aumentar el rendimiento de las inserciones al relajar las propiedades ACID (atomicidad, consistencia, aislamiento, durabilidad) en el procesamiento de transacciones. En el lado positivo, puede aumentar drásticamente el número de inserciones por segundo. La desventaja es que ahora tiene un mayor riesgo de pérdida de datos.

While most attempts to increase performance need some sacrifices, I had always thought that there was one tried and true method to increase database performance across the board – throw hardware at the problem. However, this case has shown me that, in certain situations, adding resources can cut performance – perhaps even dramatically.

 

Detalles de la gestión de la memoria

El cliente al que me refiero tiene una aplicación que necesita manejar grandes ráfagas de inserciones de registros – perhaps 10 million new records inserted into the database at a time. The application requires persistent storage so una base de datos pura en memoria no era suficiente y escribir los datos incluso en las unidades más rápidas no siempre cumplía con los requisitos de rendimiento. Después de hacer un análisis con nuestro equipo de ingeniería, se decidió que la solución a corto plazo para el problema era ejecutar la aplicación en un servidor que tuviera suficiente RAM para almacenar en caché incluso la ráfaga de inserción más grande esperada en la caché antes de confirmar la transacción y escribir en el disco. . Al aumentar el número total de páginas de caché y el tamaño de cada página, podrían caber el bloque de transacciones más grande esperado en aproximadamente 40 GB de RAM.

Armados con ese conocimiento, equiparon un servidor con 128 GB de RAM y 16 núcleos de procesador. Cuando ejecutaron la aplicación en el nuevo servidor, los resultados fueron decididamente decepcionante. En lugar de aumentar el rendimiento utilizando los recursos disponibles en la máquina, el rendimiento de la base de datos se redujo; de hecho, la primera ejecución de prueba tomó tanto tiempo que finalmente se rindieron y terminaron el proceso.

Para tratar de ayudar al cliente a comprender lo que estaba pasando y decidir si había algo en nuestro código, o en el de ellos, que se pudiera hacer para mejorar la situación, realizamos muchas pruebas.

 

¿Nos volvemos virtuales?

Lo primero que vimos fue la E / S de disco. Un error común que veo en nuestra base de clientes es solicitar más páginas de caché de base de datos de las que puede manejar la cantidad de memoria física disponible para su uso. Esto puede causar una degradación extrema del rendimiento, ya que el sistema operativo comenzará el proceso de memoria virtual escribiéndola en el disco. Si bien el servidor en este caso de prueba fue diseñado específicamente para manejar la carga esperada de la aplicación, queríamos asegurarnos de que el sistema operativo manejara la caché como esperábamos. Nuestro análisis mostró que no se estaban realizando más E / S de las esperadas por las operaciones solicitadas por la aplicación. Se estaba utilizando la memoria persistente disponible y el proceso no se virtualizó.

 

¿Podemos manejar una gran cantidad de páginas?

Lo siguiente que vimos fue cómo manejamos nuestra caché de base de datos interna. En Servidor RDM la caché de la base de datos se utiliza para almacenar partes modificadas de la base de datos hasta que se confirma una transacción y el cambio se escribe en el disco. Una preocupación era que nuestro algoritmo para buscar páginas de caché no se escalaba lo suficientemente bien como para manejar la gran cantidad de páginas de caché solicitadas por esta aplicación. El análisis demostró que el algoritmo hash utilizado para buscar páginas era tan eficiente con un gran número de páginas como con un número más moderado de páginas que se utilizan en escenarios más típicos.

 

¿Por qué tarda tanto en apagarse?

El análisis continuo reveló que las inserciones de procesamiento en las ejecuciones de prueba progresaban en la cantidad de tiempo esperada. Sin embargo, una vez que se completó el procesamiento de la inserción, la aplicación tardó horas (en lugar de segundos) en cerrarse. La creación de perfiles y la depuración mostraron que el tiempo inesperado después de completar las inserciones se dedicó a liberar la memoria asignada para las páginas de caché. Cada operación gratuita tuvo un promedio de aproximadamente 13 milisegundos. Con más de 2.621.440 páginas de caché asignadas, se calculó que se necesitarían más de 5 horas para liberar completamente toda la memoria. Para fines de comparación, en una máquina de desarrollo que usa solo 12 GB de caché (1,572,864 páginas de 8K), la caché completa se liberó en 3.48 segundos (2 microsegundos por libre).

Para aislar el comportamiento, se creó una aplicación muy simple que asignó memoria y luego la liberó en bloques de diferentes tamaños. Ejecutamos esta prueba asignando diferentes cantidades de memoria para varios tamaños de bloque y graficamos los resultados.

 

Asignación de memoria en el centro de datos de Windows Server 2008 R2

El gráfico para la asignación de memoria se veía como se esperaba. La asignación de memoria lleva más tiempo cuando se utilizan tamaños de bloque más pequeños porque se requieren más asignaciones, pero los gráficos son todos lineales para los diferentes tamaños de bloque. Al ejecutar / graficar los resultados de la liberación de memoria, encontramos una historia muy diferente.
 
Asignación de memoria en el centro de datos de Windows Server 2008 R2

 

Memoria libre en Windows Server 2008 R2 Datacenter

What isn’t very easy to see on the chart is that memory free operations are linear for 1K, 2K, 4K, and 8K block sizes. What is very easy to see is that when using a block size of 16K (actually any block larger than 16,343 bytes) freeing memory is not a linear operation, particularly if you are allocating more than 6GB. This behavior was causing the degradation in performance.
 
Memoria libre en Windows Server 2008 R2 Datacenter

 

Prueba de cordura

Decidimos ejecutar la prueba en un sistema operativo diferente para confirmar nuestros resultados. Compilamos el mismo código fuente y ejecutamos los binarios en el mismo hardware (arranque dual para Linux en lugar de Windows) y obtuvimos resultados muy diferentes.

 

Asignación de memoria en Linux

La asignación de memoria en Linux también tenía un gráfico lineal muy agradable, tomó un poco más de tiempo asignar memoria en Linux que en Windows, pero los resultados fueron similares.
 
Asignación de memoria en Linux

 

Memoria libre en Linux

Free memory on Linux was vastly different from what we saw on Windows. The free operations on Linux were much faster and more predictable than what happened on the Windows platform. Linux’s implementation in this respect was more robust and provided better scalability.
 
Memoria libre en Linux

 

¿Qué se puede hacer?

One of the most challenging things about “something that should be fast but isn’t” is figuring out how to make it fast as it should be. We were unable to find much information about this issue through web searches, but we did make one minor change to the test that proved to have good results. The original test allocated memory in the same order it was freed. By modifying the test to free memory in the reverse order, stack instead of a queue, performance was greatly improved on Windows.

 

Memoria inversa libre en el centro de datos de Windows Server 2008 R2

Si bien el gráfico no es completamente lineal, la liberación de memoria en orden inverso en Windows permite que se complete en segundos en lugar de horas cuando se utilizan tamaños de página superiores a 16K.
 
Memoria inversa en el centro de datos de Windows Server 2008 R2

 

Memoria inversa gratis en Linux

Linux también vio un aumento de rendimiento por memoria libre en el reverso de cómo se asignó, los resultados aún fueron lineales.
 
Libre de memoria inversa en Linux

Como puede ver en los gráficos, pasar a liberar memoria en el orden inverso tuvo un aumento dramático en el rendimiento. Aunque todavía no se acerca al rendimiento de la base de datos que se ve en Linux, al menos es tolerable. Esta fue una solución perfecta a corto plazo para nuestros clientes que ejecutan Windows, pero aún creemos que debería ejecutarse más rápido.

 

¿Podemos reemplazar Malloc / Free con algo mejor?

Después de validar con nuestro cliente que el cambio a datos gratuitos en orden inverso les permitió ejecutar su aplicación, decidimos ver algunas de las implementaciones alternativas de malloc proporcionadas por Microsoft. Hay varias alternativas disponibles, pero muchas de ellas son implementaciones heredadas de la era de los 16 bits. Las funciones VirtualAlloc / VirtualFree parecen ser la única alternativa viable a malloc / free. Estas funciones de memoria virtual brindan una funcionalidad más allá de lo que está disponible con malloc / free básico, pero con las opciones correctas puede usar esas funciones como un reemplazo viable para malloc / free.

Modificamos nuestro código de prueba para reemplazar la llamada a malloc con lo siguiente:

p = (MEM_CHUNK *) VirtualAlloc (NULL, chunk_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

Las llamadas gratuitas fueron reemplazadas por:

VirtualFree (p, 0, MEM_RELEASE);

We then ran the test application to allocate 24GB of memory in 1K chunks and the results were…not very good.

La máquina en la que realizamos nuestras pruebas tiene 64 GB de memoria y la mayor cantidad de memoria que esperábamos asignar en una ejecución de prueba era de 24 GB. Sin embargo, después de que nuestra ejecución de prueba no se completara en varias horas, notamos que el monitor de rendimiento mostró que nuestro proceso de prueba tenía todos los 64 GB de memoria en uso. Esto se explica fácilmente leyendo detenidamente la documentación de VirtualAlloc. El tamaño de asignación más pequeño de VirtualAlloc es una sola página de memoria. En nuestra máquina, la página de memoria tenía un tamaño de 4K, por lo que todas nuestras solicitudes de memoria de 1K en realidad estaban reservando 4K. En los límites superiores de nuestra prueba, estaríamos solicitando 96 GB de memoria en un sistema que solo tenía 64 GB disponibles. Algunas modificaciones de prueba para eliminar las ejecuciones de prueba para tamaños de página inferiores a 4K nos dieron los resultados que esperábamos.

 

VirtualAlloc en el centro de datos de Windows Server 2008 R2

VirtualAlloc no funcionó tan bien como malloc para tamaños de página más pequeños, pero para tamaños de página superiores a 16K, superó a malloc.
 
VirtualAlloc en el centro de datos de Windows Server 2008 R2

 

VirtualFree en el centro de datos de Windows Server 2008 R2

VirtualFree superó al gratuito en todos los ámbitos, especialmente con tamaños de página superiores a 16K.
 
VirtualFree en el centro de datos de Windows Server 2008 R2

 

VirtualFree inverso en el centro de datos de Windows Server 2008 R2

VirtualAlloc tuvo un rendimiento similar independientemente de la orden en que se liberó la memoria. Superó a malloc para tamaños de página superiores a 8K.
 
VirtualFree inverso en el centro de datos de Windows Server 2008 R2

Lo mejor de los resultados de VirtualAlloc / VirtualFree es que el rendimiento de la base de datos permanece constante independientemente del orden en que se libere la memoria. Al modificar nuestro código para usar VirtualAlloc para asignar búferes de más de 16K, podemos mejorar el rendimiento y la previsibilidad en los sistemas basados en Windows.

 

Conclusión

Si tiene una aplicación que utiliza una gran cantidad de asignación de memoria en fragmentos relativamente pequeños, es posible que desee considerar el uso de alternativas a malloc / free en sistemas basados en Windows. Si bien VirtualAlloc / VirtualFree no son apropiados para asignar menos de una página de memoria, pueden mejorar en gran medida el rendimiento y la previsibilidad de la base de datos al asignar memoria en múltiplos de una sola página.

Siempre es agradable cuando las cosas que deberían ser rápidas realmente lo son.

Get notified about new RDM updates

Be the first to know about new Raima Database Manager updates when they go live, use cases, industry trends and more.