Optimización del rendimiento de la base de datos: grupo de conexiones de la base de datos

Artículo de: diseño de sistema concurrente de mil millones de niveles de Alibaba (versión 2021)

Enlace: https://pan.baidu.com/s/1lbqQhDWjdZe1CBU-6U4jhA Código de extracción: 8888 

Tabla de contenido

A continuación, entremos formalmente al curso.

Entonces, ¿por qué la creación frecuente de conexiones provoca un tiempo de respuesta lento? Veamos una prueba real.

Utilice el grupo de conexiones para establecer una conexión de base de datos por adelantado

Pre-crear subprocesos con grupo de subprocesos

Resumen del curso


En los cursos anteriores, lo llevé desde una perspectiva macro para comprender los conceptos básicos del diseño de sistemas de alta concurrencia.Como ya sabe, el propósito de nuestro diseño de sistemas es obtener un mejor rendimiento, mayor disponibilidad y capacidades de expansión del sistema más sólidas.

Entonces, a partir de esta conferencia, ingresamos formalmente al capítulo de evolución. Comenzaré desde la parte y los llevaré uno por uno a comprender algunos de los métodos utilizados para completar estos objetivos. Estos métodos resolverán específicamente los problemas en el diseño de alta concurrencia. sistemas. Por ejemplo, en la conferencia 15, mencionaré el filtro Bloom. Este componente es para resolver el problema de cómo mejorar la tasa de aciertos de caché tanto como sea posible cuando hay una gran cantidad de penetración de caché.

Por supuesto, simplemente explicar la teoría y explicar el plan será aburrido, por lo que usaré un sistema virtual como línea principal a lo largo del curso para explicar qué problemas encontraremos cuando el sistema alcance una cierta etapa, y luego qué tipo de Qué ¿Están los puntos técnicos involucrados en el proceso de respuesta? A través de esta forma de decirlo, intente utilizar casos que generen problemas,

Puede hacerle saber cuál es la solución cuando se encuentra con diferentes problemas. Por supuesto, en este proceso, espero que pueda pensar más y luego aplicar el conocimiento que aprende a proyectos reales.

A continuación, entremos formalmente al curso.

Imagínese tal escenario. Un día, el director ejecutivo de la empresa lo llamó a la sala de conferencias y le dijo que la empresa vio una nueva oportunidad comercial. Espero que pueda guiar a un hermano a desarrollar rápidamente un sistema de comercio electrónico para una determinada vertical campo . En el caso de escasez de mano de obra y tiempo insuficiente, para poder completar la tarea, no dudó en adoptar la arquitectura más simple: un servidor web en el front-end ejecuta el código comercial y un servidor de base de datos en las tiendas de back-end. datos comerciales. Este diagrama de arquitectura es el prototipo de arquitectura más familiar y simple para cada uno de nosotros.Muchos sistemas se ven así al principio, pero a medida que aumenta la complejidad del negocio, la arquitectura se superpone y luego se ve cada vez más compleja.

Hablemos de nuestro sistema de comercio electrónico vertical. Después del lanzamiento del sistema, aunque la cantidad de usuarios era pequeña, funcionaba sin problemas. Tiene una sensación de logro. Sin embargo, el director ejecutivo consideró que la cantidad de usuarios era demasiado pequeña. Así que movilizó urgentemente a los estudiantes operativos para hacer una promoción de tráfico de toda la red. Esta promoción trajo rápidamente una gran ola de tráfico, pero en este momento, la velocidad de acceso del sistema comenzó a disminuir.

Después de analizar el registro del programa, encuentra que la razón del sistema lento está en la interacción con la base de datos . Porque la forma en que se llama a su base de datos es obtener primero una conexión de base de datos, luego confiar en esta conexión para consultar datos de la base de datos y finalmente cerrar la conexión para liberar recursos de la base de datos . En este método de llamada, la conexión debe restablecerse cada vez que se ejecuta SQL, por lo que se pregunta si se necesita mucho tiempo para establecer una conexión de base de datos con frecuencia y causa el problema de acceso lento .

Entonces, ¿por qué la creación frecuente de conexiones provoca un tiempo de respuesta lento? Veamos una prueba real.

Utilicé el comando "tcpdump -i bond0 -nn -tttt port 4490" para capturar los paquetes de red del establecimiento de conexión MySQL en línea para su análisis. A partir de los resultados de la captura de paquetes, todo el proceso de conexión MySQL se puede dividir en dos partes:

La primera parte son los primeros tres paquetes. El primer paquete de datos es un paquete "SYN" enviado por el cliente al servidor, el segundo paquete es un paquete "ACK" y un paquete "SYN" devuelto por el servidor al cliente, y el tercer paquete es un retorno del cliente El paquete "ACK" del servidor, los estudiantes familiarizados con el protocolo TCP pueden ver que se trata de un proceso de protocolo de enlace de tres vías TCP.

La segunda parte es el proceso de verificación de la contraseña del cliente en el servidor MySQL. El primer paquete es un paquete que el servidor envía al cliente para solicitar autenticación, el segundo y tercer paquete son paquetes que el cliente envía la contraseña encriptada al servidor, y los dos últimos paquetes son el servidor de regreso al cliente Mensaje de autenticación OK . En la figura, puede ver que todo el proceso de conexión tomó aproximadamente 4 ms (969012-964904).

Entonces, ¿cuál es el tiempo de ejecución de un solo SQL? Hemos contado el tiempo de ejecución de SQL durante un período de tiempo y encontramos que el tiempo de ejecución promedio de SQL es de aproximadamente 1 ms, lo que significa que el proceso de establecer una conexión en MySQL es más tiempo -consumo en comparación con la ejecución de SQL. Esto tiene poco efecto cuando el volumen de solicitudes es pequeño, porque se necesitan milisegundos para establecer una conexión o ejecutar SQL. Sin embargo, después de que surgió la cantidad de solicitudes, si solo se ejecutaba un SQL para establecer una conexión de la forma original, solo se podían ejecutar 200 consultas de base de datos en 1s, y el tiempo para establecer una conexión a la base de datos representaba 4/5 .

¿Qué quieres hacer en este momento? Después de algunas búsquedas en Google, descubrió que la solución también es muy simple, siempre que la conexión a la base de datos esté preestablecida utilizando el grupo de conexiones, de modo que no sea necesario crear una conexión. con frecuencia al usarlo . Después del ajuste, encontrará que se pueden ejecutar 1000 consultas a la base de datos en 1 segundo y el rendimiento de las consultas ha mejorado enormemente.

Utilice el grupo de conexiones para establecer una conexión de base de datos por adelantado

Aunque el problema se resolvió en poco tiempo, aún desea comprender a fondo el principio fundamental para resolver el problema, por lo que comienza a inventar lecciones nuevamente. De hecho, usaremos muchos grupos de conexiones en el proceso de desarrollo, como el grupo de conexiones de la base de datos, el grupo de conexiones HTTP, el grupo de conexiones de Redis, etc. Y la gestión es el núcleo del diseño del grupo de conexiones del grupo de conexiones , tomaré el grupo de conexiones de la base de datos, por ejemplo, para ilustrar los puntos clave de la gestión del grupo de conexiones.

El grupo de conexiones de la base de datos tiene dos configuraciones más importantes: el número mínimo de conexiones y el número máximo de conexiones, que controlan el proceso de obtención de conexiones del grupo de conexiones:

  1. Si el número actual de conexiones es menor que el número mínimo de conexiones, cree una nueva conexión para procesar la solicitud de la base de datos;
  2. Si hay conexiones inactivas en el grupo de conexiones, reutilice las conexiones inactivas;
  3. Si no hay ninguna conexión en el grupo libre y el número actual de conexiones es menor que el número máximo de conexiones, se crea una nueva conexión para procesar la solicitud;
  4. Si el número actual de conexiones es mayor o igual que el número máximo de conexiones, espere a que la conexión anterior esté disponible según el tiempo establecido en la configuración (la configuración del grupo de conexiones de C3P0 es checkoutTimeout);
  5. Si el tiempo de espera excede este tiempo establecido, se lanzará un error al usuario.

No necesitas memorizar este proceso, es muy simple. Puede detenerse y pensar en cómo diseñaría si fuera el diseñador del grupo de conexiones y cuáles son los puntos clave. Esta idea de diseño se utilizará a menudo en nuestro futuro diseño de arquitectura.

Para facilitar su comprensión del proceso de la memoria sexual, permítame darle un ejemplo. Suponga que tiene una pequeña tienda de sillones de masaje en el aeropuerto. Hay un total de 10 sillones de masaje (número máximo análogo de conexiones). Para ahorrar costos (los sillones de masaje cobran electricidad), generalmente tiene 4 sillones de masaje en la tienda. Sillones de masaje (número mínimo de conexiones), los otros 6 están cerrados. Cuando llega un cliente, si los 4 sillones de masaje que normalmente están activados están disponibles, puedes simplemente pedirle que vaya al vacío. Pero si los 4 sillones de masaje no están disponibles cuando venga el cliente, comenzará uno nuevo hasta que se agoten los 10 sillones de masaje. ¿Qué debo hacer después de que se agoten los 10 sillones de masaje? Le dirá al usuario que espere un poco, le prometo que estará disponible en 5 minutos (tiempo de espera) y luego el undécimo usuario comenzará a esperar. En este momento, habrá dos resultados: si hay un sillón de masaje gratuito en 5 minutos, entonces el cliente puede ir directamente al sillón de masaje gratuito, pero si el usuario espera 5 minutos y no está libre, entonces debe Discúlpate y deja que los usuarios vayan a otras tiendas para volver a comprobar.

Para los grupos de conexiones de bases de datos, según mi experiencia, generalmente en línea, recomiendo que la cantidad mínima de conexiones se controle en aproximadamente 10, y la cantidad máxima de conexiones se controle en aproximadamente 20 ~ 30. Aquí, debes prestar atención al mantenimiento de la conexión en la piscina, que es la silla de masaje que mencioné. Aunque algunos sillones de masaje están encendidos, a veces fallan. En circunstancias normales, el "fallo del sillón de masaje" puede deberse a las siguientes razones:

  1. La IP correspondiente al nombre de dominio de la base de datos ha cambiado, y la conexión al grupo todavía usa la IP antigua.Cuando se cierra el servicio de base de datos bajo la IP antigua, se producirá un error cuando se vuelva a utilizar la consulta de conexión;
  2. MySQL tiene un parámetro "wait_timeout", que controla cuánto tiempo está inactiva la conexión de la base de datos antes de que la base de datos cierre activamente la conexión. Este mecanismo no es consciente del usuario de la base de datos, por lo que se producirán errores cuando usemos esta conexión cerrada.

Entonces, como propietario de una tienda de sillones de masaje, ¿cómo garantiza que el sillón de masaje que ha activado debe estar disponible?

  1. Inicie un hilo para verificar periódicamente si la conexión en el grupo de conexiones está disponible. Por ejemplo, use la conexión para enviar un comando "seleccionar 1" a la base de datos para ver si se lanzará una excepción. Si se lanza una excepción, elimine el conexión desde el grupo de conexiones e intente apagar. En la actualidad, el grupo de conexiones C3P0 puede usar este método para detectar si la conexión está disponible, que también es mi método preferido.
  2. Después de obtener la conexión, primero verifique si la conexión está disponible y ejecute la instrucción SQL si está disponible. Por ejemplo, el elemento de configuración testOnBorrow del grupo de conexiones DBCP controla si se habilita esta verificación. Este método introducirá una sobrecarga adicional al obtener una conexión. Intente no habilitarlo en el sistema en línea, ya que puede usarse en servicios de prueba.
  3. En este punto, ha entendido completamente el principio de funcionamiento del grupo de conexiones. Sin embargo, cuando solo quería dar un suspiro de alivio, el CEO presentó un nuevo requisito. Analizó este requisito y encontró que en una interfaz muy importante, necesita acceder a la base de datos tres veces. A juzgar por la experiencia, cree que este lugar definitivamente se convertirá en un cuello de botella del sistema en el futuro.

Pensando más, cree que puede crear varios subprocesos para procesar la interacción con la base de datos en paralelo, de modo que la velocidad pueda ser más rápida. Sin embargo, debido a las lecciones de la última base de datos, cree que en la etapa de alta concurrencia, la sobrecarga de crear subprocesos con frecuencia será muy alta, así que continúe pensando en las ideas anteriores y adivine el grupo de subprocesos.

Pre-crear subprocesos con grupo de subprocesos

Efectivamente, el ThreadPoolExecutor introducido en JDK 1.5 es una implementación de un grupo de subprocesos. Tiene dos parámetros importantes: coreThreadCount y maxThreadCount. Estos dos parámetros controlan la ejecución del grupo de subprocesos. Su principio de ejecución es similar al modelo de tienda de sillones de masaje que mencionamos anteriormente, te lo describiré para profundizar tu memoria:

  1. Si el número de subprocesos en el grupo de subprocesos es menor que coreThreadCount, se crearán nuevos subprocesos al procesar nuevas tareas;
  2. Si el número de subprocesos es mayor que coreThreadCount, la tarea se coloca en una cola y el subproceso actualmente inactivo la ejecuta;
  3. Cuando las tareas en la cola estén llenas, continúe creando subprocesos hasta que se alcance maxThreadCount;
  4. Cuando el número de subprocesos alcanza maxTheadCount, hay nuevas tareas enviadas, por lo que tenemos que descartarlas.

Este proceso de procesamiento de tareas parece simple, pero de hecho hay muchas trampas, debe prestar atención al usar:

En primer lugar, el grupo de subprocesos implementado por el JDK prioriza las tareas en la cola para el almacenamiento temporal, en lugar de crear más subprocesos. Es más adecuado para realizar tareas intensivas de CPU, es decir, tareas que requieren muchas operaciones de CPU . Debido a que la CPU está ocupada cuando se realizan tareas que requieren un uso intensivo de la CPU, solo necesita crear subprocesos con la misma cantidad de núcleos de CPU. Más subprocesos cambiarán de contexto y reducirán la eficiencia de ejecución de tareas. Por lo tanto, cuando el número actual de subprocesos excede el número de subprocesos centrales, el grupo de subprocesos no agregará subprocesos, sino que se colocará en la cola para esperar a que los subprocesos principales se liberen. Sin embargo, los sistemas web que solemos desarrollar suelen tener una gran cantidad de operaciones IO, como consultar la base de datos, consultar la caché, etc. La CPU está inactiva cuando la tarea está realizando operaciones de E / S. En este momento, si aumenta la cantidad de subprocesos que ejecutan la tarea en lugar de almacenarla temporalmente en la cola, puede realizar más tareas por unidad de tiempo, lo que mejora enormemente el rendimiento de la ejecución de la tarea la cantidad. Entonces verá que el grupo de subprocesos utilizado por Tomcat no es el grupo de subprocesos nativo de JDK, sino algunas transformaciones . Cuando el número de subprocesos excede coreThreadCount , los subprocesos se crearán primero hasta que el número de subprocesos alcance maxThreadCount , que es más adecuado para un gran número de operaciones IO en sistemas web También puede consultarlo en el proceso de solicitud real.

En segundo lugar, la acumulación de colas utilizadas en el grupo de subprocesos también es un indicador importante que debemos monitorear. Este indicador es particularmente crítico para tareas con altos requisitos de tiempo real. Me he encontrado con un problema extraño en el proyecto real de que la tarea no se ha ejecutado durante mucho tiempo después de haber sido lanzada al grupo de subprocesos. Al principio, pensé que esto se debía a un error en el código. Después de la investigación, se descubrió que las configuraciones coreThreadCount y maxThreadCount del grupo de subprocesos eran relativamente pequeñas, lo que provocó que se acumulara una gran cantidad de tareas en el grupo de subprocesos. El problema ocurrió después de aumentar estos dos parámetros. Está resuelto. Después del salto fuera del pozo, coloqué la cantidad de acumulación de la cola de tareas de un grupo de subprocesos importante, como un indicador importante del sistema de monitoreo colocado en un monitor de pantalla grande .

Finalmente, si usa grupos de subprocesos, recuerde no usar colas ilimitadas (es decir, no se establecen colas de tamaño fijo) . Quizás sientas que después de usar la cola ilimitada, la tarea nunca se descartará, siempre y cuando la tarea no requiera un alto rendimiento en tiempo real, de todos modos, habrá un día de consumo. Sin embargo, la acumulación de una gran cantidad de tareas ocupará una gran cantidad de espacio de memoria. Una vez que el espacio de memoria esté lleno, el GC completo se activará con frecuencia, lo que hará que el servicio no esté disponible . El tiempo de inactividad causado por un GC que he verificado antes es causado por un sistema en el sistema. El grupo de subprocesos utiliza una cola ilimitada.

Comprenda los puntos clave del grupo de subprocesos, agregue esta función al sistema, hasta ahora, el sistema es estable, completó con éxito las tareas de investigación y desarrollo de la empresa por usted.

En este momento, si analiza estas dos tecnologías, encontrará que tienen una cosa en común: los objetos que administran, ya sean conexiones o subprocesos, requieren mucho tiempo para crear y consumir recursos del sistema. Por lo tanto, los ponemos en un grupo para una gestión unificada para lograr el propósito de mejorar el rendimiento y la reutilización de recursos.

Esta es una idea común de diseño de software, denominada tecnología de agrupación. Su idea central es el espacio para el tiempo. Se espera que utilice objetos creados previamente para reducir la sobrecarga de rendimiento de la creación frecuente de objetos. Al mismo tiempo, los objetos se pueden administrar de manera uniforme Reducir el costo de uso del objeto , en definitiva, hay muchos beneficios.

Sin embargo, la tecnología de agrupación también tiene algunos inconvenientes. Por ejemplo , los objetos en la agrupación de almacenamiento deben consumir un exceso de memoria. Si los objetos no se utilizan con frecuencia, se producirá una pérdida de memoria . Por ejemplo, los objetos del grupo deben crearse con anticipación cuando se inicia el sistema, lo que aumenta el tiempo de inicio del sistema hasta cierto punto .

Pero estos defectos son relativamente triviales en comparación con las ventajas de la tecnología de agrupación. Siempre que confirmemos que los objetos que se utilizarán consumen mucho tiempo o recursos cuando se crean, y que estos objetos se crean y destruyen con frecuencia, lo haremos Puede utilizar la tecnología de agrupación para optimizar.

Resumen del curso

En esta lección, simulé el escenario más primitivo del desarrollo de un sistema de comercio electrónico vertical. Cuando encontramos el problema de la degradación del rendimiento de las consultas de la base de datos, usamos el grupo de conexiones de la base de datos para resolver el problema de rendimiento causado por la creación frecuente de conexiones, y luego usamos el grupo de subprocesos para mejorar Mejorar el rendimiento de la base de datos de consultas paralelas.

De hecho, los grupos de conexiones y los grupos de subprocesos no son desconocidos para usted, pero es posible que aún tenga confusión o malentendidos sobre sus principios y uso. Durante la entrevista, descubrí que muchos estudiantes no entendían el uso básico de los grupos de subprocesos. Tomando prestada esta lección, quiero enfatizar nuevamente los puntos clave:

La configuración de los valores máximos y mínimos de la piscina es muy importante, puede configurarla basándose en la experiencia en la etapa inicial, pero aún necesita ajustarla de acuerdo con las condiciones reales de operación .

Los objetos del grupo deben inicializarse antes de su uso. Esto se denomina calentamiento del grupo . Por ejemplo, cuando se utiliza el grupo de subprocesos, es necesario inicializar todos los subprocesos principales por adelantado. Si el grupo no se calienta, puede causar solicitudes más lentas después de que se reinicia el sistema .

El núcleo de la tecnología de pooling es una práctica de métodos de optimización del espacio-por-tiempo, por lo que debemos prestar atención a la ocupación del espacio para evitar problemas como el uso excesivo del espacio, fugas de memoria o recolecciones frecuentes de basura .

Supongo que te gusta

Origin blog.csdn.net/sanmi8276/article/details/113093169
Recomendado
Clasificación