Solicitudes de página de administración de larga duración que bloquean otras solicitudes

17

Si he iniciado sesión en el backend de Magento y realizo alguna tarea que lleva mucho tiempo (búsqueda global en catálogos grandes, flujo de datos de larga ejecución, etc.), mi navegador web se negará a cargar otras páginas administrativas solo en ese navegador . ¿Por qué sucede esto? ¿Existe alguna ciencia conocida para soluciones alternativas?

Es decir, si yo

  1. Inicie sesión en la página del panel de Magento

  2. Abra una segunda pestaña con cualquier página de administración de Magento

  3. Realice una búsqueda global de larga duración (simulada con una llamada al sleep(30)inicio de globalSearchAction) en la primera pestaña

  4. Intenta volver a cargar la segunda pestaña

Comportamiento esperado: la segunda pestaña se carga con el contenido de la página inmediatamente

Comportamiento real: la segunda pestaña solo se carga una vez que se completa la búsqueda global de larga duración

¿Alguien sabe, específicamente, por qué sucede esto? (Supongo que las solicitudes de la consola de administración de Magento bloquean algunos recursos que Magento necesita para arrancar, pero no sé qué es eso)

¿Alguien sabe de una solución / solución?

Alan Storm
fuente
1
¡Usted, señor, acaba de enviarme a un desafío! :)
davidalger

Respuestas:

21

El problema es causado por un bloqueo colocado por el controlador de sesión PHP. Por lo tanto, no se trata de que Magento bloquee explícitamente algo e intente bloquear las solicitudes de administración, sino casi un efecto secundario per-se del almacenamiento de sesión basado en archivos.

Un bloqueo de escritura se lo coloca en el archivo de datos de sesión cuando se abre por la solicitud inicial (de larga duración), haciendo que la segunda solicitud al bloque hasta que el bloqueo se libera cuando se llama session_startenMage_Core_Model_Session_Abstract_Varien::start

Esto es 100% reproducible. Usé el mismo método que usaste, agregando un sleep(30)a la parte superior deMage_Adminhtml_IndexController::globalSearchAction

Vale la pena señalar que esto no se puede reproducir si está utilizando el almacenamiento de sesión db. Después de encontrar la causa raíz, configuré un sandbox para el almacenamiento de sesión db y ya no pude reproducir el problema. Por lo tanto, los manejadores de sesión de db que Magento aparentemente no utiliza el bloqueo de nivel de fila para bloquear las escrituras de sesión. Esto me parece interesante, ya que tiene el potencial de pérdida de datos de la sesión, ya que la aplicación obviamente no tiene en cuenta múltiples hilos que escriben en la misma sesión. Nota para los lectores: nunca usaría el almacenamiento de sesión db en producción para tratar de resolver esto, solo es bueno para sobrecargar su base de datos MySql.

No intenté reproducir el comportamiento utilizando sistemas de almacenamiento de sesión basados ​​en memoria como Redis, pero supongo que el bloqueo de los registros en el almacén de sesión probablemente también se pasó por alto en estos.

Hay técnicas que podrían emplearse para evitar esto, como usar session_write_closepara liberar el bloqueo antes de comenzar un trabajo de larga duración. Pero esto también le impediría escribir en la sesión ya que la acaba de cerrar. Por lo tanto, no es probable que se implemente fácilmente en todos los ámbitos en Magento, pero podría implementarse en rutas / controladores específicos.

Mi técnica para fijar esto como la causa raíz era habilitar el perfilador Xdebug y examinar el archivo "cachegrind". Una vez que se completó la segunda solicitud, cargué el archivo de salida (~ 25 MB de registro) en MacCallGrind y profundicé en el seguimiento siguiendo la ruta de las llamadas donde el tiempo de inclusión fue de 28 segundos o más. Esto finalmente me llevó a la session_startllamada, que tardó unos 28 segundos en ejecutarse, lo que me dio un gran punto para investigar.

EDITAR: Para los interesados, publiqué una captura de pantalla del archivo "cachegrind" visto en MacCallGrind en Twitter.

davidalger
fuente
El módulo uRapidFlow de Unirgy cierra la sesión para evitar este problema, que en cierto modo es agradable, pero es frustrante en la medida en que dificulta la retroalimentación al usuario posterior.
Peter O'Callaghan
@davidalger: ¿con qué almacenamiento de sesión normalmente se implementa para sitios de clientes?
Alan Storm
3
Re: bloqueando el archivo de sesión PHP, esto es menos para la integridad de los datos que para la integridad del archivo en el disco. Tener múltiples procesos que se abren y escriben en bits en el disco (que es lo que es un archivo) conducirá rápidamente a la corrupción de los datos. MySQL, redis y la mayoría de las bases de datos están diseñadas específicamente para mantenerse consistentes, incluso si hay múltiples escrituras casi al mismo tiempo. es decir, no es que se haya pasado por alto el bloqueo, es que no es tan críticamente necesario.
Alan Storm
@AlanStorm: una instancia de Memcached dedicada para una instalación con equilibrio de carga, sistema de archivos para clústeres de nodo de aplicación única. El sistema de archivos funciona mejor donde no tiene múltiples nodos ya que no tiene latencia IP.
davidalger
Correcto, bloquear el archivo se trata de prevenir la corrupción de datos. Sin embargo, mantener el bloqueo hasta que se cierre la sesión se trata de evitar la pérdida de datos. Si dos procesos cargan los datos de la sesión, los modifican y luego los escriben, uno de ellos tendrá sus modificaciones sobrescritas. En general, no va a plantear un problema crítico, pero podría causar pérdida de datos y / o problemas desagradables y difíciles de depurar.
davidalger