Compartir vía


Incluir en contenedores las aplicaciones de Java

En este artículo se proporciona información general sobre las estrategias y la configuración recomendadas para la contenedorización de aplicaciones Java.

Al incluir en contenedores una aplicación De Java, tenga en cuenta cuidadosamente cuánto tiempo de CPU tendrá disponible el contenedor. A continuación, tenga en cuenta la cantidad de memoria disponible en términos de cantidad total de memoria y el tamaño del montón de la máquina virtual Java (JVM). En entornos en contenedores, las aplicaciones pueden tener acceso a todos los procesadores y, por tanto, pueden ejecutar varios subprocesos en paralelo. Sin embargo, es habitual que los contenedores tengan aplicada una cuota de CPU que pueda limitar el acceso a las CPU.

JVM tiene heurística para determinar el número de "procesadores disponibles" en función de la cuota de CPU, lo que puede influir considerablemente en el rendimiento de las aplicaciones Java. La memoria asignada al propio contenedor y el tamaño del área de montón de la JVM son tan importantes como los procesadores. Estos factores determinarán el comportamiento del recolector de elementos no utilizados (GC) y el rendimiento general del sistema.

Contenedorización de una nueva aplicación

Al incluir en contenedores una carga de trabajo de Java para una nueva aplicación, debe tener en cuenta dos cosas al pensar en la memoria:

  • Memoria asignada al propio contenedor.
  • Cantidad de memoria disponible para el proceso de Java.

Descripción de la ergonómica predeterminada de JVM

Las aplicaciones necesitan un punto de partida y una configuración. JVM tiene la ergonómica predeterminada con valores predefinidos que se basan en el número de procesadores disponibles y la cantidad de memoria en el sistema. Los valores predeterminados que se muestran en las tablas siguientes se usan cuando se inicia la JVM sin marcas de inicio o parámetros específicos.

En la tabla siguiente se muestra el GC predeterminado usado para los recursos disponibles:

Recursos disponibles GC predeterminado
Cualquier número de procesadores
Hasta 1791 MB de memoria
SerialGC
Más de 2 procesadores
1792 MB o más de memoria
G1GC

En la tabla siguiente se muestra el tamaño máximo predeterminado del montón en función de la cantidad de memoria disponible en el entorno en el que se ejecuta la JVM:

Memoria disponible Tamaño máximo predeterminado del montón
Hasta 256 MB 50 % de la memoria disponible
256 MB a 512 MB ~127 MB
Más de 512 MB 25 % de la memoria disponible

El tamaño del montón inicial predeterminado es 1/64 de memoria disponible.

Estos valores son válidos para OpenJDK 11 y versiones posteriores, y para la mayoría de las distribuciones, como Microsoft Build de OpenJDK, Azul Zulu, Eclipse Temurin, Oracle OpenJDK y otros.

Determinación de la memoria del contenedor

Elija una cantidad de memoria de contenedor que sirva mejor la carga de trabajo, según las necesidades de la aplicación y sus patrones de uso distintivos. Por ejemplo, si la aplicación crea gráficos de objetos grandes, probablemente necesitará más memoria de la que necesitaría para las aplicaciones con muchos gráficos de objetos pequeños.

Sugerencia

Si no sabe cuánta memoria asignar, un buen punto de partida es de 4 GB.

Determinación de la memoria del montón de JVM

Al asignar memoria del montón de JVM, tenga en cuenta que la JVM necesita más memoria que lo que se usa para el montón de JVM. Cuando se establece la memoria máxima del montón de JVM, nunca debe ser igual a la cantidad de memoria del contenedor, ya que esto provocará errores de memoria insuficiente (OOM) del contenedor y bloqueos de contenedor.

Sugerencia

Asigne el 75 % de la memoria del contenedor para el montón de JVM.

En OpenJDK 11 y versiones posteriores, puede establecer el tamaño del montón de JVM de las maneras siguientes:

Descripción Marca Ejemplos
Valor fijo -Xmx -Xmx4g
Valor dinámico -XX:MaxRAMPercentage -XX:MaxRAMPercentage=75

Tamaño mínimo o inicial del montón

Cuando se garantiza que el entorno tiene una cierta cantidad de memoria reservada a una instancia de JVM, como en un contenedor, debe establecer el tamaño mínimo del montón (o el tamaño inicial del montón) en el mismo tamaño que el tamaño máximo del montón. Esta configuración indica a la JVM que no debe realizar la tarea de liberar memoria al sistema operativo.

Para establecer un tamaño mínimo de montón, use -Xms para cantidades absolutas o -XX:InitialRAMPercentage para cantidades porcentuales.

Importante

La marca -XX:MinRAMPercentage, a pesar de lo que sugiere el nombre, se usa para establecer el porcentaje de RAM máximo predeterminado para los sistemas con hasta 256 MB de RAM disponibles en el sistema.

Gráfico que muestra el tamaño del montón predeterminado en OpenJDK 17.

Determinar qué GC se va a usar

Anteriormente, determinó la cantidad de memoria del montón de JVM con la que empezar. El siguiente paso es elegir la GC. La cantidad máxima de memoria del montón de JVM que tiene suele ser un factor en la elección de la GC. En la tabla siguiente se describen las características de cada GC.

Factores SerialGC ParallelGC G1GC ZGC ShenandoahGC
Número de núcleos 1 2 2 2 2
Multiproceso No
Tamaño del montón de Java <4 GBytes <4 GBytes >4 GBytes >4 GBytes >4 GBytes
Pausar Sí (<1 ms) Sí (<10 ms)
Gastos generales Mínimo Mínimo Moderado Moderado Moderado
Efecto de latencia de cola Alto Alto Alto Bajo Moderada
Versión de JDK All All JDK 8+ JDK 17+ JDK 11+
Más adecuado para Montones pequeños de núcleo único Montones pequeños de varios núcleos o cargas de trabajo por lotes con cualquier tamaño de montón Capacidad de respuesta en montones medianos y grandes (interacciones de solicitud-respuesta/base de datos) Capacidad de respuesta en montones medianos y grandes (interacciones de solicitud-respuesta/base de datos) Capacidad de respuesta en montones medianos y grandes (interacciones de solicitud-respuesta/base de datos)

Sugerencia

Para la mayoría de las aplicaciones de microservicios de uso general, comience con la GC paralela.

Determinar cuántos núcleos de CPU se necesitan

Para cualquier GC que no sea SerialGC, se recomiendan dos o más núcleos de vCPU, o al menos 2000m cpu_limit en Kubernetes. No se recomienda seleccionar nada menos de 1 núcleo de vCPU en entornos en contenedores.

Sugerencia

Si no sabe cuántos núcleos empezar, una buena opción es 2 núcleos de vCPU.

Selección de un punto de partida

Se recomienda empezar con dos réplicas o instancias en entornos de orquestación de contenedores como Kubernetes, OpenShift, Azure Spring Apps, Azure Container Apps y App de Azure Service. En la tabla siguiente se resumen los puntos de partida recomendados para la contenedorización de la nueva aplicación Java.

vCPU cores Memoria de contenedor Tamaño del montón de JVM GC Réplicas
2 4 GB El 75 % ParallelGC 2

Los parámetros de JVM que se van a usar son: -XX:+UseParallelGC -XX:MaxRAMPercentage=75

Contenedorización de una aplicación existente (local)

Si la aplicación ya se está ejecutando de forma local o en una máquina virtual en la nube, se recomienda empezar por:

  • La misma cantidad de memoria a la que tiene acceso la aplicación actualmente.
  • El mismo número de CPU (núcleos de vCPU) que la aplicación tiene disponible actualmente.
  • Los mismos parámetros de JVM que usa actualmente.

Si los núcleos de vCPU o la combinación de memoria del contenedor no están disponibles, elija el más cercano, redondeando los núcleos de vCPU y la memoria del contenedor.

Pasos siguientes

Ahora que comprende las recomendaciones generales para la inclusión en contenedores de aplicaciones Java, continúe con el siguiente artículo para establecer una línea de base de contenedorización: