[Java Virtual Machine] Caso de ajuste y análisis de JVM práctica integral

1. ¿Qué es la optimización del rendimiento de JVM?

La optimización del rendimiento de JVM involucra dos conceptos muy importantes: rendimiento y tiempo de respuesta. El ajuste de JVM es principalmente para ajustarlos y optimizarlos para lograr un objetivo ideal y determinar si el objetivo es priorizar el rendimiento o el tiempo de respuesta de acuerdo con el negocio.

  • Rendimiento: tiempo de ejecución del código de usuario / (tiempo de ejecución del código de usuario + tiempo de ejecución del GC).
  • Tiempo de respuesta: el tiempo de respuesta de toda la interfaz (tiempo de ejecución del código de usuario + tiempo de ejecución del GC), cuanto menor sea el tiempo STW, menor será el tiempo de respuesta.

Metodología de ajuste

  • Supervisar el rendimiento de JVM

    • Supervise el estado de ejecución de la JVM para comprender los cuellos de botella de la aplicación y los cuellos de botella del rendimiento
    • Puede usar las herramientas que vienen con la JVM, como jstat, jmap, jstack, etc., o herramientas de terceros, como VisualVM, JProfiler, etc.
  • Puntos de referencia para las pruebas de estrés

    • Realice una prueba de presión en el programa para obtener el rendimiento y el tiempo de respuesta correspondientes a la interfaz
    • Fenómeno externo
      • Para la experiencia del usuario, es la velocidad de respuesta.
      • Puede usar la herramienta de medición de presión jmeter para realizar mediciones de presión para obtener indicadores de rendimiento relevantes
    • Fenómeno interno:
      • El análisis de la situación del GC es un factor importante en el ajuste del rendimiento de la JVM. Es necesario dominar el mecanismo de trabajo del GC y el significado de los registros del GC.
      • Puede usar el registro de GC que viene con la JVM o herramientas de terceros, como GCEasy, para analizar la situación de GC y comprender la frecuencia, el tiempo, el uso de memoria, etc.
  • Ajustar los parámetros de JVM

    • Mejore el rendimiento de la aplicación ajustando parámetros como el tamaño del almacenamiento dinámico, el algoritmo de GC, el tamaño del grupo de subprocesos, etc.
    • Nota: Diferentes aplicaciones y entornos pueden requerir diferentes configuraciones de parámetros de JVM, como aplicaciones con uso intensivo de IO y uso intensivo de CPU
  • Análisis de estrés secundario

    • Después de ajustar los parámetros de jvm, la segunda prueba de presión para ver si los indicadores de rendimiento mejoran o disminuyen
    • Interno: registro de GC, ver rendimiento, tiempos de GC, cambios de tiempo de pausa
    • Externo: si el rendimiento y el tiempo de respuesta correspondientes a la interfaz son mejores
  • Otros métodos de optimización

    • optimizar código

      • Optimice su código evitando la creación de objetos innecesarios, reduciendo las operaciones de sincronización, usando cachés, etc.
      • Nota: La optimización del código debe seguir el principio de "corregir primero, luego optimizar" y no debe sacrificar la legibilidad y el mantenimiento del código.
    • Usar programación concurrente

      • Use subprocesos múltiples, grupo de subprocesos, etc. para mejorar el rendimiento de la concurrencia, como ajustar la longitud de la cola del grupo de subprocesos, la cantidad de subprocesos supervivientes, etc.
      • Nota: la programación concurrente debe tener en cuenta cuestiones como la seguridad de subprocesos y la competencia de bloqueos, y requiere un diseño e implementación correctos
    • usar caché

      • Puede usar caché local, caché distribuida, etc. para mejorar el rendimiento del acceso a datos
      • Nota: El almacenamiento en caché debe tener en cuenta cuestiones como la coherencia y la invalidación de la memoria caché, y requiere un diseño y una implementación correctos.
    • Evite el bloqueo de E/S

      • Use IO asíncrono, NIO, etc. para mejorar el rendimiento de IO, como el arreglo de tareas asíncronas CompletableFuture aprendido anteriormente
      • Nota: la programación de IO debe considerar cuestiones como la concurrencia y la confiabilidad, y requiere un diseño e implementación correctos
    • Tecnología distribuida + clúster

      • Utilice la tecnología de equilibrio de carga + clúster para mejorar la capacidad de procesamiento de un solo nodo

2. Preparación del entorno de prueba de presión de ajuste de JVM

  • El programa jar escrito por SpringBoot, la interfaz devuelve una lista de objetos compuestos aleatoriamente dentro de 100 (usando JDK17)
/**
 * @author lixiang
 * @date 2023/5/8 21:44
 */
@Slf4j
@RestController
@RequestMapping("/spring-test")
public class SpringTestController {
    
    

    @RequestMapping("query")
    public Map<String, Object> query() throws InterruptedException {
    
    

        int num = (int) (Math.random() * 100) + 1;
        //申请5MB内存
        Byte[] bytes = new Byte[5 * 1024 * 1024];

        List<Product> productList = new ArrayList<>();
        for (int i = 0; i < num; i++) {
    
    
            Product product = new Product();
            product.setPrice((int) Math.random() * 100);
            product.setTitle("商品编号" + i);
            productList.add(product);
        }

        Thread.sleep(5);
        Map<String, Object> map = new HashMap<>(16);
        map.put("data", productList);
        return map;

    }

}
  • Preparación de la herramienta de prueba de presión Jmeter, plan de prueba 200 concurrencia, ciclo 500 veces

3. Configuración del tamaño del almacenamiento dinámico para la optimización del rendimiento de JVM

  • Configuración del tamaño del almacenamiento dinámico, impacto en el rendimiento de los tiempos de FullGC
  • Valor inicial optimizado para el rendimiento
-Xms1g # 配置初始堆内存1G
-Xmx1g # 配置最大堆内存1G
-XX:+UseG1GC # 使用G1回收器
-XX:MaxGCPauseMillis=200 # 设置最大停顿时间200ms
-XX:G1HeapRegionSize=32M # 设置G1每个region块大小为32M
-XX:ActiveProcessorCount=8 # 设置JVM使用的CPU核数限制为8
-XX:+HeapDumpOnOutOfMemoryError # 当JVM发生OOM时,自动生成DUMP文件
-XX:HeapDumpPath=heapdump.hprof # DUMP文件路径
-XX:+PrintCommandLineFlags # 监控开启
-Xlog:gc=info:file=portal_gc.log:utctime,level,tags:filecount=50,filesize=100M 
  # Xlog:指定日志输出方式为日志文件。
  # gc*:指定日志输出类型为GC相关的日志。
  # info:指定输出日志的级别为info级别。
  # file=portal_gc.log:指定日志输出的文件名为portal_gc.log。
  # utctime:指定日志输出的时间戳使用UTC时间。
  # level,tags:指定日志输出的格式包含级别和标签信息。
  # filecount=50:指定最多保存50个日志文件。
  # filesize=100M:指定每个日志文件的大小为100MB。
  • La configuración de la máquina es: ancho de banda de 8 núcleos 16G 500M

inserte la descripción de la imagen aquí

  • Establezca la memoria de pila inicial y la memoria de pila máxima en 1G, prueba de presión
nohup java -jar spring-test-1.0-SNAPSHOT.jar -Xms1g -Xmx1g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=32M -XX:ActiveProcessorCount=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/jmeter/heapdump.hprof -XX:+PrintCommandLineFlags -Xlog:gc=info:file=/usr/local/jmeter/portal_gc.log:utctime,level,tags:filecount=50,filesize=100M &

inserte la descripción de la imagen aquíinserte la descripción de la imagen aquí

Cuando configuramos la memoria del montón en 1 G, el rendimiento general es superior al 40 %, lo que ya es muy bajo. Durante este período, Young GC se produjo 7451 veces y Full GC se produjo 142 veces.

  • Establezca la memoria de pila inicial y la memoria de pila máxima en 2G, prueba de presión
nohup java -jar spring-test-1.0-SNAPSHOT.jar -Xms2g -Xmx2g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=32M -XX:ActiveProcessorCount=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/jmeter/heapdump.hprof -XX:+PrintCommandLineFlags -Xlog:gc=info:file=/usr/local/jmeter/portal_gc.log:utctime,level,tags:filecount=50,filesize=100M &

inserte la descripción de la imagen aquíinserte la descripción de la imagen aquí

Cuando configuramos la memoria del montón en 2G, en comparación con 1G, el rendimiento aumentó a más del 70 %, y la cantidad de Young GC fue 752, y la cantidad de Full GC fue 6 veces, que se duplicó en comparación con 1G.

  • Establezca la memoria de pila inicial y la memoria de pila máxima en 4G, prueba de presión
nohup java -jar spring-test-1.0-SNAPSHOT.jar -Xms4g -Xmx4g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=32M -XX:ActiveProcessorCount=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/jmeter/heapdump.hprof -XX:+PrintCommandLineFlags -Xlog:gc=info:file=/usr/local/jmeter/portal_gc.log:utctime,level,tags:filecount=50,filesize=100M &

inserte la descripción de la imagen aquíinserte la descripción de la imagen aquí

Cuando la memoria del montón se establece en 4G, el rendimiento general aumenta al 76 %, se produce 504 en el GC joven y no se produce ningún GC completo.

  • Establezca la memoria de pila inicial y la memoria de pila máxima en 6G, prueba de presión
nohup java -jar spring-test-1.0-SNAPSHOT.jar -Xms6g -Xmx6g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=32M -XX:ActiveProcessorCount=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/jmeter/heapdump.hprof -XX:+PrintCommandLineFlags -Xlog:gc=info:file=/usr/local/jmeter/portal_gc.log:utctime,level,tags:filecount=50,filesize=100M &

inserte la descripción de la imagen aquíinserte la descripción de la imagen aquí

Cuando la memoria del montón se establece en 6 G, el rendimiento general alcanza el 87 %, el GC Yong se produce 196 veces y el GC completo se produce 0 veces.

Resumen: a través del ajuste de la memoria del montón, se encuentra que 4G es la configuración de parámetros con la mayor relación de entrada-salida, por lo que la configuración actual puede usar la memoria del montón 4G.

4. Configuración del recopilador para la optimización del rendimiento de JVM

A través de la configuración de la memoria en montón anterior, podemos concluir que 4G es la mejor memoria en montón para la máquina actual y la configuración de la aplicación. Aquí no cambiamos el tamaño de la memoria en montón, pero usamos 4G de la memoria en montón y cambiamos la basura colector para ver el impacto en el rendimiento de la interfaz.

Aquí usamos ParallelGC. Actualmente, el recolector de basura G1 es la mejor opción para aplicaciones con una gran cantidad de concurrencia. Aquí usamos principalmente ParallelGC para una comparación.

nohup java -jar spring-test-1.0-SNAPSHOT.jar -Xms4g -Xmx4g -XX:+UseParallelGC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=32M -XX:ActiveProcessorCount=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/jmeter/heapdump.hprof -XX:+PrintCommandLineFlags -Xlog:gc=info:file=/usr/local/jmeter/portal_gc.log:utctime,level,tags:filecount=50,filesize=100M &

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/weixin_47533244/article/details/130582772
Recomendado
Clasificación