viernes, 11 de septiembre de 2020

Mejorando la performance de la JVM en un contenedor

 Para poder configurar la JVM dentro de un contenedor para que este pueda escalar de manera correcta es necesario poder tomar memoria y liberar memoria de forma correcta.

Para ello tendremos que hacer cierta configuraciones que serán pasadas en parámetros al ejecutar la aplicación. 

Primer paso

A partir de la versión 10 de Java es necesario utilizar el parámetro -XX:+UseContainerSupport para indicarle a la JVM que esta ejecutándose dentro de un contenedor Docker o algún otro contenedor.

También es necesario definir que cantidad de memoria que se utiliza dentro del contenedor y para esto lo mejor es definir un porcentaje por si se le llega asignar mas memoria a la RAM, la JVM pueda tener mas memoria disponible para tomar. Para ello se utiliza el parámetro -XX:MaxRAMPercentage y se le pasa el porcentaje que toma la JVM. Ejemplo:

-XX:MaxRAMPercentage=80

Liberar memoria RAM dentro del contenedor

Una de las mejores herramientas que tienen los gestor de contenedores como (Kubernetes, etc.) es que pueden crear contenedores automáticamente en paralelo para que estos puedan tomar toda la carga tanto de trafico como de procesamiento de los Request en el caso de una API por ejemplo. Hay varias formas de escalar contenedores ya sea por superar un cierto porcentaje de la RAM y/o del uso de CPU. 

Para el caso de la RAM es necesario de que la JVM libere la memoria para que luego de que baje el trafico o el procesamiento el gestor de contenedores pueda dar de baja los contenedores que se generaron para hacer de soporte a los pedidos.

Dependiendo de que versión tengamos de la JVM utilicemos deberemos pasar parámetros o no. Si tenemos la versión 8 de Java el Garbage Collector que utilice es el ParallelGC y en Java 11 el default el Garbage Collector G1. Lo que se recomienda para liberar memoria es que utilices el default de Java 8 y si estas en Java 11 hagas el cambio de GC, con el siguiente parámetro -XX:+UseParallelGC

Ademas de configurar el margen de memoria libre dentro de la memoria Heap de Java utilizando los siguiente parámetros:

-XX:MinHeapFreeRatio=10
-XX:MaxHeapFreeRatio=10


Ejemplo

En el ejemplo siguiente se utilizo los parámetros dentro de una JVM 11:

-XX:MaxRAMPercentage=80
-XX:MinHeapFreeRatio=10
-XX:MaxHeapFreeRatio=10

Primero no se selecciono ningún GC, lo cual se utilizo el default de la JVM 11 que es el GC1 y el resultado es el siguiente 

Prueba con GC1

Como se ve la memoria Heap de Java va tomando memoria a medida que la necesita pero luego de ejecutar los requests libera memoria dentro del Heap pero no libera memoria al Sistema Operativo. 

Por otro lado vamos a agregar el parámetro -XX:+UseParallelGC para ver el comportamiento del mismo procesamiento anterior y como va tomando y liberando memoria. 

Prueba con GC Parallel

Ahora podemos observar que efectivamente a medida que no necesita RAM la va liberando del Heap y también la va liberando al Sistema Operativo. Siempre manteniendo tomada un 10% de la memoria.


Conclusión

Si llevamos a cabo las configuraciones recomendadas podemos optimizar el uso de contenedores dentro del Gestor de contenedores (Ej, Kubernetes) y liberar memoria dentro de los contenedores para avisarle al Gestor que ya puede eliminar los contenedores ya que bajo la carga de procesamiento.

No hay comentarios:

Publicar un comentario