Fundamentos de JVM para Elasticsearch: métricas, memoria y monitoreo

Elasticsearch es un motor de analítica y búsqueda basado en Java y una base de datos vectorial construida sobre Apache Lucene, y es el núcleo de Elasticsearch Platform. Para ejecutar Elasticsearch en sus plataformas compatibles, necesitas una máquina virtual Java (JVM). La JVM proporciona un entorno de ejecución independiente de la Platform, y puedes ejecutar Elasticsearch en un entorno virtual sobre el sistema operativo existente. La JVM abstrae el sistema operativo y el hardware subyacentes, por lo que las aplicaciones Java pueden ejecutarse en cualquier Platform.
Comprender la gestión de memoria de la JVM y la recolección de objetos mediante la recolección de basura (GC) es la clave para solucionar problemas como java.lang.OutOfMemoryError (código de salida 127). Estos problemas ocurren cuando la JVM se ejecuta sin memoria o cuando hay un código de salida 137, lo que normalmente indica que el killer de memoria insuficiente (OOM) del host terminó el proceso de la JVM debido a un uso excesivo de memoria. Este blog te guiará sobre cómo examinar los patrones de uso de memoria y solucionar estos problemas de JVM.
También explicaré el papel de la JVM y cómo correlacionar esto con la ayuda de las API de Elasticsearch existentes, proporcionando información valiosa sobre el estado de la JVM de Elasticsearch y ayudándote a decidir si quieres ajustarla aún más según tu propio caso de uso.
Como se menciona en la documentación de JVM de Elasticsearch, los valores predeterminados de las opciones de JVM que se envían con el producto funcionan de manera eficiente en todos los entornos de producción compatibles; estos valores predeterminados pueden manejar la mayoría de los casos de uso para operaciones de búsqueda e indexación. No se recomienda cambiar ningún valor ni agregar valores personalizados para las opciones o configuraciones de JVM.
Si crees que algún cambio sería beneficioso para tu carga de trabajo, ponte en contacto con Soporte de Elastic antes de hacerlo.
¿Qué es una JVM?
Una máquina virtual de Java es una parte integral del Java Runtime Environment (JRE), que viene incluido en un Java Development Kit (JDK).

La JVM es similar a un programa informático que ayuda a ejecutar aplicaciones Java. No existe como una máquina física, pero actúa como tal al traducir el código Java en instrucciones que su sistema operativo compatible puede entender. La JVM también se encarga de tareas importantes como la gestión de memoria, el manejo de la recolección de basura y mantener sus aplicaciones seguras.
A continuación, centrémonos en la gestión de memoria de JVM y la recolección de basura —un punto importante en Elasticsearch que verificamos con frecuencia al solucionar cualquier problema de rendimiento de memoria o relacionado con OOM.
Para entender la gestión de memoria y la recolección de basura, primero debes entender la representación lógica del área heap (o memoria heap) donde residen todos los objetos cuando se inicia una JVM.
Comprender la memoria heap de JVM: generaciones joven y antigua
Un área de heap, o memoria heap, es una combinación de pools de memoria donde viven los objetos según su ciclo de vida y antigüedad. Una memoria heap de JVM consiste principalmente en una young generation y una old generation. La young generation se divide aún más en regiones Eden y Survivor, como se ilustra a continuación. Los objetos Java se asignan en estas áreas según su antigüedad y referencia, y luego se mueven de las regiones young a las old.
La mayor parte de la utilización de heap en el espacio Eden se recolecta rápidamente. Cualquier heap que no se libere se mueve a uno de los espacios survivor (S0 o S1), donde normalmente se recupera siguiendo un patrón de decaimiento exponencial. Si persiste más allá de esto, se mueve al espacio Tenured.
Memoria heap total de JVM = Generación joven (regiones Eden y Survivor S0 y S1) + Generación antigua (Tenured)

Área/región de young generation
Cuando cualquier aplicación de Java se inicia, crea nuevos objetos y los asigna al área llamada memoria heap. El espacio Eden de la young generation es el primer lugar donde la aplicación asigna los objetos recién creados. Esta área está reservada para la asignación de nuevos objetos. Y cuando se llena, los objetos elegibles serán eliminados (garbage collected) o promovidos a otras regiones.
Cuando ocurre una recolección de basura menor, los objetos referenciados se moverán a otra subsección que es la región Survivor S0. Y los objetos no referenciados se eliminarán para liberar espacio en Eden. Esta región contiene los objetos que sobrevivieron al proceso de recolección de basura, de ahí el nombre región Survivor.
El mismo ciclo se repite cuando el espacio Eden vuelve a estar lleno. Esta vez, los objetos que sobrevivieron tanto a Eden como a S0 se moverán a la región S1, y este proceso continúa.
Los objetos que sobrevivieron a las recolecciones de basura en Eden, S0 y S1 serán promovidos a la generación antigua según el calculador de antigüedad.
Área/región de old generation
La old generation (también conocida como tenured generation) es una colección de objetos de larga duración que sobrevivieron a los múltiples eventos de recolección de basura en la young generation (GC menores). Los objetos que han sobrevivido a un cierto número de ciclos en el survivor space son movidos por el algoritmo a la old generation, también conocida como promoción de objetos.

El patrón de GC en diente de sierra anterior del monitoreo de pilas muestra que, cuando ocurre una recolección de basura menor, la memoria heap de la JVM se reduce porque el GC elimina los objetos no deseados de la memoria. Después de algunos ciclos, los objetos se acumulan y el GC entra en acción de nuevo para limpiar los objetos.
Método de recolección de basura
Elasticsearch se envía con una versión de JDK incluida compatible, y los detalles están documentados en las notas de lanzamiento. Hasta la v6.4, Elasticsearch utilizaba el recolector de basura concurrent mark sweep (CMS), que quedó obsoleto en JDK9. Ahora, Elasticsearch utiliza el recolector de basura Garbage-First (G1) como método de GC predeterminado. También tiene un mejor rendimiento en comparación con el método de GC CMS. El mecanismo interno de G1GC es complejo e involucra muchas fases, pero analicemos sus aspectos básicos.
Para usar G1GC, utiliza el flag de JVM -XX:+UseG1GC en la opción de JVM de Elasticsearch. En G1GC, el área total de heap se dividirá en regiones de igual tamaño -XX:G1HeapRegionSize=1m, que pueden variar de 1 MB a 32 MB según el tamaño del heap. Las generaciones Eden, Survivor y old son conjuntos lógicos de estas regiones y no son contiguas. Además de esto, hay una región humongous y una libre/disponible dentro del área de heap. La región humongous se utiliza para asignar objetos que tienen más de la mitad del tamaño de la región.

El G1GC tiene un objetivo de tiempo de pausa (-XX:MaxGCPauseMillis=200) que intenta cumplir durante la recolección de basura. Esto significa que, durante la recolección de basura, se asegura de que la JVM no experimente una pausa mayor a este valor, lo que lo hace mejor que CMS u otros recolectores donde esta no es una opción. En general, se recomienda mantener la configuración de GC con los valores predeterminados, lo que mantendrá la pausa de GC dentro de los límites para un rendimiento mejorado.
API de Elasticsearch para el estado de la JVM
Cualquier tarea que Elasticsearch desee realizar necesitará pedirle a la JVM que asigne algo de memoria para poder ejecutarla. Como se mencionó anteriormente, la JVM maneja la gestión de memoria en nombre de Elasticsearch para que no tenga que preocuparse por ello. Sin embargo, los administradores pueden estar interesados en verificar el estado de la JVM a través de las API de Elasticsearch para asegurarse de que todo avance según lo esperado.
Para verificar todas las configuraciones que se han especificado o proporcionado como argumentos de entrada para la JVM de Elasticsearch, utiliza la API de información del Node con el atributo JVM (también descrito en la documentación).
GET _nodes/_all/jvm Esta API proporcionará los detalles de la configuración de Node, incluidos los argumentos de entrada de JVM, los pools de memoria y el tamaño del heap.
Además, si quieres verificar las métricas de la JVM de Elasticsearch para el tiempo de actividad de un nodo en particular, el heap utilizado en todos los pools de memoria o estadísticas sobre la recolección de basura, puedes usar la API de estadísticas de Node. Proporcionará métricas detalladas sobre cada una de las métricas mencionadas.
GET _nodes/stats/jvm
or
GET _nodes/stats/jvm?filter_path=nodes.*.jvmNota: Elasticsearch no recomienda tomar decisiones basadas en el valor heap_percent obtenido de la API de estadísticas de Node. Nuestra UI sí calcula la presión de memoria, y el usuario debe tomar las medidas necesarias según el cálculo descrito en este blog.
Comprobación de métricas de JVM mediante la herramienta de JDK integrada
Si eres un usuario avanzado y quieres verificar estadísticas en tiempo real sobre una JVM en ejecución sin usar las API de Elasticsearch, puedes usar el Java agrupado y ejecutar jstat para verificar las estadísticas en vivo. Para hacer esto, primero encuentra el directorio de inicio de Java o el directorio bin y el PID del proceso de Elasticsearch. Desde el directorio bin, usa la herramienta jstat:
./jstat -gcutil <PID> 2000Aquí, 2000 es el intervalo en milisegundos después del cual se recuperarán e imprimirán las estadísticas en la CLI. Este comando es útil para identificar con qué frecuencia ocurre GC en todas las áreas y qué tan rápido se llenan los pools de memoria con los objetos (tasas de creación y promoción de objetos).
Esto no es una alternativa a las API mencionadas arriba, sino que es más para depuración a nivel de desarrollador.
¡Eso es todo!
En este blog, cubrimos los conceptos básicos de las máquinas virtuales Java, varios grupos de memoria, la importancia de la recolección de basura y cómo verificar las estadísticas de JVM de Elasticsearch. En el próximo blog, discutiremos las configuraciones importantes de JVM y cómo consultar sus métricas actuales dentro de Elasticsearch.
Si tienes preguntas o deseas obtener más soporte, no dudes en comunicarte con nosotros. ¡Siempre estamos aquí para ayudarte y nos complace hacerlo!
El momento del lanzamiento de cualquiera de las características o funcionalidades descritas en esta publicación queda a exclusivo criterio de Elastic. Es posible que algunas características o funcionalidades que no estén disponibles en este momento no se lancen a tiempo o no se lancen en absoluto.