Proceso de solución de problemas de rendimiento

Escenario del proyecto:

Grabar una solución de problemas de rendimiento


Descripción del problema

Hace algún tiempo, la prueba planteó un problema de rendimiento y luego lo analizó. Esta interfaz es una interfaz de menú, que requiere un rendimiento relativamente alto. El tiempo de solicitud del entorno de prueba es de 500 concurrentes, aproximadamente 2,5 segundos, pero el requisito real está dentro de 1s, por lo que es Para analizar este problema.


Análisis de causa:

1. La lógica principal del código.

En el primer paso, primero analizamos el código de este método. La lógica del código tiene varias partes. 1. Obtener información del usuario en redis 2. Realizar estadísticas sobre las visitas al menú y usar la información del usuario en el primer paso 3. Obtener de redis Información del menú 4. Si se obtiene la información del menú, regrese directamente, si no se obtiene la información, consulte la información del menú de la base de datos.

2. Análisis preliminar

En términos generales, no hay problema con la lógica del código. Primero, se realizó una impresión de registro preliminar, como obtener información del usuario, funciones estadísticas y obtener información del menú de redis. Tomó tiempo imprimir y luego probar en el entorno de prueba. , y descubrí que obtener información de redis es básicamente básico. Todos ellos están por encima de los 500ms. Si consulta desde la base de datos, el tiempo será más largo, básicamente alrededor de 7s.

3. Optimización preliminar

En primer lugar, optimizamos los problemas que podemos ver, por ejemplo, 1. La obtención de información del usuario en redis es imprescindible, por lo que no se puede omitir 2. La estadística de visitas, que no está directamente relacionada con la función de obtener menús, se pueden colocar Ir al grupo de subprocesos asíncronos para ejecutar, no es necesario ejecutar en el subproceso principal. 3. Al obtener el menú de la base de datos, la instrucción sql se asocia con una tabla de aplicación. Se debe obtener un nombre de aplicación. Use el método de unión izquierda y hay una operación detrás. La operación puede tener rendimiento. problemas, entonces optimice Bajo el sql, las condiciones donde se verifican en la tabla de menú, así que coloque estas condiciones en la tabla de menú para verificar, y luego únase a la tabla de aplicaciones en forma de una tabla temporal para obtener la información de la tabla de aplicaciones , de modo que la tabla de control sea la más pequeña. Establecer combinación puede mejorar el rendimiento y verificar si el índice se usa correctamente y si se establece el índice.

4. Prueba de nuevo

Después de hacer los cambios anteriores, probamos nuevamente, pero los resultados no fueron satisfactorios. Los resultados fueron mejores, pero el impacto no fue significativo. También lo analizamos más tarde. Los cambios anteriores pueden mejorar un poco, pero la cantidad de datos en el El entorno de prueba en sí es pequeño. No es muy grande, y los cambios en sql no se pueden medir, pero ahorra algo de tiempo para las estadísticas de ejecución asíncrona.

5. Pruebas locales

Como no podemos probarlo en el entorno, podemos probarlo directamente localmente, lo cual es conveniente para depurar problemas.La prueba de inicio local es de 500 concurrentes y el tiempo es de 4,5 s porque la computadora local no es tan buena como la servidor Es comprensible, pero no afecta el rendimiento de depuración. Entonces sospeché que era un problema con redis. Revisé los registros y descubrí que se accedió a la base de datos muchas veces durante el proceso de solicitud. El tiempo de caducidad de la configuración de redis era de 3 minutos, pero parecía caducar en un segundo. Para ignore el impacto de este problema, establezca el tiempo de caducidad en Establecer para que no caduque y pruebe de nuevo.

6. Prueba de nuevo

Después de configurar el tiempo de caducidad, la base de datos ya no se solicita con frecuencia, es aproximadamente 1 segundo más rápida, 3,5 segundos, pero sigue siendo muy lenta.

7. Análisis

Vi que la tasa de descarga es de 950kb, la respuesta a una solicitud es de aproximadamente 2.5kb, 500 de concurrencia, es decir, 1M de datos, 950kb es casi lo mismo, el ancho de banda no es la razón del impacto y luego continúe revisando redis, usamos jedis, y luego optimicé los parámetros del grupo de conexiones jedis, cambié try(resource){} para usar jedispool.returnResource y lo volví a colocar en el grupo de conexiones, y los parámetros del grupo de conexiones aumentaron

        poolConfig.setTimeBetweenEvictionRunsMillis(5000);
        poolConfig.setMinEvictableIdleTimeMillis(60000);
并且把原来只有100个连接改成了500个
    poolConfig.setMaxTotal(500);
    poolConfig.setMaxIdle(500);
    poolConfig.setMinIdle(10);
    poolConfig.setMaxWaitMillis(1000);    

8. prueba

La prueba nuevamente encontró que 1 s se redujo a 2.5 s. Con algunas optimizaciones, el código para obtener información del usuario y estadísticas de tráfico se comentó directamente más adelante. La prueba fue de 1.4 s y 1 s se redujo.

9. Análisis

Luego me pregunté si era el problema de redis del servidor. Instalé redis localmente para probar, me conecté a mi redis local y lo reemplacé con mi redis local. Seguía siendo el mismo y estaba casi al borde del colapso. . . Luego comprobé que la versión de redis es 3.1.200. Me preguntaba si mi versión era demasiado baja. Luego fui a instalar una versión superior a Windows 6.0 y la depuré toda la mañana. Como resultado, la versión instalada que se encuentra en Windows era básicamente inutilizable. , es fácil fallar y salir del proceso. Más tarde, descubrí que redis no es compatible con Windows, y luego instalé una máquina virtual localmente, instalé la versión redis6.2.5 en la máquina virtual y habilité subprocesos múltiples Después de comprender Redis, debe saber que la compatibilidad con subprocesos múltiples se puede habilitar después de la versión 6.0.
En el archivo redis.conf, cambie no por sí y cambie el hilo, que generalmente es consistente con la cantidad de núcleos de CPU.

# io-threads-do-reads no
# io-threads 4

(Más tarde, se descubrió que la versión redis y los subprocesos múltiples tienen una influencia casi nula, no influyen en los factores)

10. Configuración de parámetros de Windows

El noveno paso anterior tomó más de medio día y luego ajustó los parámetros de las ventanas.
Uno es la configuración del número de identificadores, y el otro es la configuración del número de conexiones tcp. Hágalo más grande. No afecte el número de simultaneidad debido a estos Publicaré el enlace de depuración para los parámetros, y puede encontrarlos usted mismo.
Límite de manejo

  1. https://www.lmlphp.com/user/16721/article/item/460591/
    límite de conexión tcp
  2. https://blog.imdst.com/windows-xia-dan-ji-zui-da-tcplian-jie-shu/
    (Esta no es la causa del problema, pero también le da una dirección para pensar)

11. Prueba

Luego, al iniciar el proyecto, use java -jar para comenzar, verifique el posible impacto de la idea y el resultado aún está optimizado. El resultado final es de aproximadamente 1.3 s. Mirando el registro, la solicitud redis toma 500 ms. Este resultado es 500ms en comparación con el principio. Se ha optimizado mucho, pero todavía no está bien. Es solo 500 de concurrencia. ¿Cómo puede llevar tanto tiempo llegar desde redis? Redis no es tan malo, y no es una llave grande. Los datos son solo 2.5kb y no es una clave grande.

12. Análisis

Luego continué leyendo el registro, solicité una vez, luego leí el registro de solicitud completo y descubrí que había muchas veces en el registro para obtener información del usuario, y luego busqué el registro en el código y descubrí que el registro múltiple anterior código de inquilino, para el grupo de conexiones de redis Se realiza una intercepción aop, es decir, se intercepta redis y se agrega la información del usuario a la clave de redis, que se intercepta dos veces. Ambos métodos son @around y se obtiene la información del inquilino from redis en @around (operación redis),
es decir, cada vez que se opera redis se ejecutarán cuatro operaciones *2,8, porque redis se opera en el método aspect, se ejecuta around antes y después, y esta vez encontramos el problema más influyente. Comenté esta clase directamente y luego probé

13. Prueba

De nuevo, la prueba es muy rápida. En el caso de la concurrencia 500, la solicitud redis toma muy poco tiempo, a veces 0 ms, puede ser muy rápido, la máquina no parece consumir mucho tiempo y el tiempo total es de 100 ms, es decir , de 1.3s a 100ms, este tramo tardó más de 1s.


solución:

La solución final es eliminar la operación de facetas de redis e implementarla de otras maneras. Se encontró que la causa raíz final es causada por la operación de facetas de redispool, por lo que todos deben tener cuidado al operar facetas, especialmente para la clase de utilidad frecuente. usar.

Resumir

Llevó casi una semana realizar esta optimización del rendimiento y finalmente se encontró el problema. El resumen es que la optimización del rendimiento requiere la comprensión de muchas cosas, incluida la verificación del rendimiento de la máquina durante la prueba, la observación de la CPU, la memoria, el ancho de banda y el rendimiento del disco. , ya sea un problema de la máquina que limita la concurrencia, o un problema de red, o un problema de código, y el problema de código implica sincronizar todas las operaciones, optimización de sql, optimización de índice, optimización de grupo de conexiones redis, etc. Es fácil de analizar uno por uno para ver el resultado, pero no es fácil averiguarlo.

Supongo que te gusta

Origin blog.csdn.net/qq_34526237/article/details/127168831
Recomendado
Clasificación