2012-03-11 13 views
7

Mi aplicación MySQL experimenta bajo rendimiento al ejecutar algunas consultas UPDATE, INSERT y DELETE. En esta pregunta, solo hablaré de un particular UPDATE, porque es suficiente para demostrar el problema:¿Puede la latencia de I/O causar una ACTUALIZACIÓN simple para tomar segundos en MySQL?

UPDATE projects SET ring = 5 WHERE id = 1 

Este UPDATE es por lo general lo suficientemente rápido, alrededor de 0,2 ms, pero de vez en cuando (lo suficiente como para ser un problema) tarda varios segundos. He aquí un extracto del registro (mirar la cuarta línea):

~ (0.000282) UPDATE `projects` SET `ring` = 5 WHERE `id` = 1 
~ (0.000214) UPDATE `projects` SET `ring` = 6 WHERE `id` = 1 
~ (0.000238) UPDATE `projects` SET `ring` = 7 WHERE `id` = 1 
~ (3.986502) UPDATE `projects` SET `ring` = 8 WHERE `id` = 1 
~ (0.000186) UPDATE `projects` SET `ring` = 9 WHERE `id` = 1 
~ (0.000217) UPDATE `projects` SET `ring` = 0 WHERE `id` = 1 
~ (0.000162) UPDATE `projects` SET `ring` = 1 WHERE `id` = 1 

projects es una tabla InnoDB con 6 columnas de tipos INT y VARCHAR, 17 filas y un índice en id. Sucede con otras tablas también, pero aquí me estoy enfocando en esta. Al tratar de resolver el problema, me aseguré de que las consultas fueran todas secuenciales, así que esto es , no es un problema de bloqueo. El UPDATE anterior se ejecuta en el contexto de una transacción. Otro información en el servidor:

  • VPS con 4 GB de RAM (1 GB fue), el espacio libre en disco 12 GB
  • CentoOS 5,8 (5,7)
  • MySQL 5.5.10 (era 5.0.x)

El bit "was" anterior significa que no funcionó antes o después de la actualización.

Lo que he probado hasta ahora, en vano:

  • Configuración innodb_flush_log_at_trx_commit a 0, 1 ó 2
  • Configuración innodb_locks_unsafe_for_binlog dentro o fuera de
  • Configuración timed_mutexes dentro o fuera de
  • Cambiando innodb_flush_method de forma predeterminada a O_DSYNC o O_DIRECT
  • El aumento innodb_buffer_pool_size del valor predeterminado a 600M y luego a 3000M
  • El aumento innodb_log_file_size del valor predeterminado a 128M
  • la compilación de MySQL desde el código fuente
  • Correr SHOW PROCESSLIST, que me informa de que el estado es "actualización"
  • Correr SHOW PROFILE ALL , que dice que casi todo el tiempo se gastó en "actualizar" y que, dentro de ese paso, no se gastaba tanto tiempo en ciclos de CPU y había muchos cambios de contexto voluntarios (como 30)
  • Monitoreando SHOW STATUS para ver cambios en Innodb_buffer_pool_pages_dirty. Puede haber alguna relación entre las páginas sucias que se vacían y las consultas lentas, pero la correlación no es clara.

Luego decidí verificar la latencia de E/S del sistema con ioping.Esta es mi primera VPS, por lo Me sorprendió ver este resultado:

4096 bytes from . (vzfs /dev/vzfs): request=1 time=249.2 ms 
4096 bytes from . (vzfs /dev/vzfs): request=2 time=12.3 ms 
4096 bytes from . (vzfs /dev/vzfs): request=3 time=110.5 ms 
4096 bytes from . (vzfs /dev/vzfs): request=4 time=232.8 ms 
4096 bytes from . (vzfs /dev/vzfs): request=5 time=294.4 ms 
4096 bytes from . (vzfs /dev/vzfs): request=6 time=704.7 ms 
4096 bytes from . (vzfs /dev/vzfs): request=7 time=1115.0 ms 
4096 bytes from . (vzfs /dev/vzfs): request=8 time=209.7 ms 
4096 bytes from . (vzfs /dev/vzfs): request=9 time=64.2 ms 
4096 bytes from . (vzfs /dev/vzfs): request=10 time=396.2 ms 

Bastante irregular, diría.

Una vez dicho todo esto, pregunto:

  1. Puede ser latencia en ocasiones matar el rendimiento de E/S de MySQL? Siempre pensé que, cuando ejecutaba un UPDATE, el hilo que se encargaba de esa conexión no iba a vaciar datos en el disco ni esperar a tal enrojecimiento; volvería inmediatamente y el enrojecimiento sería hecho por otro hilo en otro momento.

  2. Si no puede ser E/S de disco, ¿hay algo más que pueda probar, salvo alquilar un servidor dedicado?

+0

¿Es el COMPROMISO el que tarda 5 segundos o la ACTUALIZACIÓN real? –

+0

El actual 'ACTUALIZACIÓN'. –

+0

'UPDATE' debería normalmente, como dices, no estar al ras en el disco, solo' COMMIT' vaciará el registro mientras se ejecuta en tu hilo (y innodb_flush_log_at_trx_commit = 0 debería desactivarlo) Tu latencia de E/S es definitivamente fuera de control (!), pero a menos que la carga sea lo suficientemente alta como para no permitir el almacenamiento en caché de la tabla de 17 filas para leer, no puedo ver cómo sería la causa de este problema exacto. –

Respuesta

2

Estoy respondiendo a mi propia pregunta con datos adicionales que recopilé en función de sus respuestas.

Utilicé dos computadoras portátiles conectadas por medio de una red inalámbrica. En el cuaderno A, I monté un directorio del bloc de notas B usando sshfs. Luego, en el notebook A, inicié MySQL especificando ese directorio montado como su directorio de datos.Esto debería proporcionar a MySQL un dispositivo de E/S muy lento. MySQL se inició con innodb_flush_log_at_trx_commit = 0.

Definí 3 series de consultas, cada conjunto que consiste en una actualización y una consulta de selección repetida 10.000 veces, sin transacciones explícitas. Los experimentos fueron:

  • US1SID: actualice y seleccione en una fila específica de la misma tabla. Se usó la misma fila en todas las iteraciones.
  • US1MID: actualice y seleccione en una fila específica de la misma tabla. La fila era diferente en cada iteración.
  • US2MID: actualice y seleccione en filas de tablas diferentes. En este caso, la tabla que leyó el seleccionador no cambió en absoluto durante el experimento.

Cada conjunto se llevó a cabo dos veces usando un script de shell (por lo tanto los tiempos son más lentos que los de mi pregunta original), uno en condiciones normales y la otra después de ejecutar el comando siguiente:

tc qdisc replace dev wlan0 root handle 1:0 netem delay 200ms 

El comando arriba agrega un retraso medio de 200 ms cuando se transmiten paquetes a través de wlan0.

En primer lugar, aquí está el tiempo medio de las mejores actualizaciones y selecciones del 99% más rápido, y el inferior 1% de actualizaciones y selecciones.

  |  Delay: 0ms  |  Delay: 200ms  | 
      | US1SID | US1MID | US2MID | US1SID | US1MID | US2MID | 
| top99%u | 0.0064 | 0.0064 | 0.0064 | 0.0063 | 0.0063 | 0.0063 | 
| top99%s | 0.0062 | 0.0063 | 0.0063 | 0.0062 | 0.0062 | 0.0062 | 
| bot01%u | 1.1834 | 1.2239 | 0.9561 | 1.9461 | 1.7492 | 1.9731 | 
| bot01%s | 0.4600 | 0.5391 | 0.3417 | 1.4424 | 1.1557 | 1.6426 | 

Como es evidente, incluso con muy, muy pobre rendimiento de E/S, se las arregla para MySQL ejecutar la mayoría de consultas muy rápido. Pero lo que más me preocupa es el peor caso de , así que aquí hay otra tabla que muestra las 10 consultas más lentas. Una "u" significa que era una actualización, una "s" a seleccionar.

|   Delay: 0ms   |   Delay: 200ms   | 
| US1SID | US1MID | US2MID | US1SID | US1MID | US2MID | 
| 5.443 u | 5.946 u | 5.315 u | 11.500 u | 10.860 u | 11.424 s | 
| 5.581 u | 5.954 s | 5.466 u | 11.649 s | 10.995 u | 11.496 s | 
| 5.863 s | 6.291 u | 5.658 u | 12.551 s | 11.020 u | 12.221 s | 
| 6.192 u | 6.513 u | 5.685 u | 12.893 s | 11.370 s | 12.599 u | 
| 6.560 u | 6.521 u | 5.736 u | 13.526 u | 11.387 u | 12.803 u | 
| 6.562 u | 6.555 u | 5.743 u | 13.997 s | 11.497 u | 12.920 u | 
| 6.872 u | 6.575 u | 5.869 u | 14.662 u | 12.825 u | 13.625 u | 
| 6.887 u | 7.908 u | 5.996 u | 19.953 u | 12.860 u | 13.828 s | 
| 6.937 u | 8.100 u | 6.330 u | 20.623 u | 14.015 u | 16.292 u | 
| 8.665 u | 8.298 u | 6.893 u | 27.102 u | 22.042 s | 17.131 u | 

Conclusiones:

  1. pobre rendimiento de E/S puede, en efecto lento MySQL a paso de tortuga. No está claro por qué o cuando exactamente, pero sucede.

  2. La ralentización se aplica a las selecciones y actualizaciones, con actualizaciones que sufren más.

  3. Por alguna razón, incluso selecciona en una mesa que no participó en ningún cambio, y que recientemente habían sido pobladas, también fueron ralentizado, como se desprende de US2MID anteriormente.

  4. En cuanto a los casos de prueba propuestos por mentatkgs, parece que la actualización de diferentes filas en lugar de las mismas no ayuda un poco, pero no resuelve el problema .

supongo que tampoco me adaptaré mi software de tolerar tales retrasos o tratar de mover a otro proveedor. Alquilar un servidor dedicado es demasiado caro para este proyecto .

Gracias a todos por los comentarios.

0

Pregunta 1) Sí.

Para comprobar que escribir 2 aplicaciones:

caso de prueba 1: va a hacer esto cada minuto durante unas horas

UPDATE `projects` SET `ring` = 5 WHERE `id` = 1 
UPDATE `projects` SET `ring` = 6 WHERE `id` = 1 

caso de prueba 2: lo hará cada minuto durante unas horas

UPDATE `projects` SET `ring` = 7 WHERE `id` = 1 
UPDATE `projects` SET `ring` = 8 WHERE `id` = 2 

El caso de prueba 1 debería tener un retraso, mientras que el caso de prueba 2 no debería tener.

Pregunta 2) Use una base de datos noSQL.

+0

En unos minutos voy a publicar una respuesta respondiendo mi pregunta. Ejecuté algunos experimentos cuyos resultados apoyan parcialmente tus argumentos. Sin embargo, el uso de NoSQL está descartado: P –

1

Como usted está alojando su VPS en la nube, es posible que se encuentre con problemas que están completamente fuera de su control.

Los VPS están sujetos a los caprichos de los servidores host que los ejecutan. Por ejemplo, la prioridad del ciclo de la CPU en la nube de Rackspace se pondera en función del tamaño del SPV. Cuanto más grande sea tu VPS, mayor será la probabilidad de que tu aplicación funcione sin problemas. Si hay un VPS más grande en el host que está utilizando, es posible que hay estallido ponderado a la culpa. Es bastante difícil de decir.

¿Ha intentado ejecutar esto localmente en su propia máquina? Si funciona perfectamente en su propio sistema y necesita un rendimiento garantizado, su mejor opción será trasladarse a un servidor dedicado.

+0

En otras máquinas funciona bien. El rendimiento es importante para mi aplicación, pero como el alquiler de un servidor dedicado sería mucho más caro, al menos por el momento intentaré adaptar el software a estos retrasos. En unos minutos publicaré algunos otros resultados que obtuve que me ayudaron a aclarar el problema. –

1

Tiene un problema de E/S relacionado con el SPV. No es culpa de MySQL.

¿Está usted por casualidad usando Elastic Block Store con Amazon, o posiblemente RDS? Ambos usan almacenamiento remoto y una capa de protocolo IP para comunicarse con el almacenamiento; pueden tener desagradable retraso a veces.

+0

Estoy usando Myhosting.com. Nunca pensé que esto fuera, por ejemplo, un error en MySQL. Simplemente no entiendo muy bien su comportamiento. (Básicamente, si una tabla está en la memoria, ¿por qué bloquea MySQL al actualizarla?) –

+0

Nunca se garantiza una tabla MySQL 'en la memoria', aunque MySQL trabajará duro para mantener los índices en la memoria. Si necesita una verdadera base de datos en memoria, entonces, dependiendo de sus requisitos, puede consultar sqlite (no es bueno para la concurrencia, pero es rápido y fácil para muchas cosas), una solución NoSQL como redis o una columna más moderna. bases de datos que ofrecen un poco más de control aquí. –

Cuestiones relacionadas