Anforderungen für Admin-Seiten mit langer Laufzeit, die andere Anforderungen blockieren

17

Wenn ich im Backend von Magento angemeldet bin und eine Aufgabe ausführe, die lange dauert (globale Suche in großen Katalogen, Datenfluss usw.), lehnt mein Webbrowser das Laden anderer Verwaltungsseiten nur in diesem Browser ab . Warum passiert das und gibt es eine bekannte Wissenschaft für Problemumgehungen?

Das ist, wenn ich

  1. Melden Sie sich auf der Dashboard-Seite von Magento an

  2. Öffnen Sie eine zweite Registerkarte mit einer beliebigen Magento-Administrationsseite

  3. Führen Sie auf der ersten Registerkarte eine globale Suche mit langer Laufzeit durch (simuliert mit einem Aufruf von sleep(30)zu Beginn globalSearchAction)

  4. Versuchen Sie, die zweite Registerkarte neu zu laden

Erwartetes Verhalten: Die zweite Registerkarte wird sofort mit dem Seiteninhalt geladen

Tatsächliches Verhalten: Die zweite Registerkarte wird erst geladen, wenn die lange laufende globale Suche abgeschlossen ist

Weiß jemand konkret, warum das passiert? (Ich vermute, dass Magento-Administratorkonsolenanforderungen eine Ressource sperren, die Magento zum Booten benötigt, aber ich weiß nicht, was das ist.)

Kennt jemand einen Fix / Workaround?

Alan Storm
quelle
1
Sie, mein Herr, haben mich gerade auf eine Herausforderung geschickt! :)
Davidalger

Antworten:

21

Das Problem wird durch eine Sperre des PHP-Session-Handlers verursacht. Es ist also nicht Magento, das explizit etwas sperrt und versucht, Administratoranforderungen zu blockieren, sondern fast ein Nebeneffekt des dateibasierten Sitzungsspeichers.

Eine Schreibsperre wird auf der Sitzungsdaten - Datei platziert , wenn es von der anfänglichen (Langlauf) Anforderung geöffnet wird, wodurch die zweite Anfrage nach Block , bis die Sperre gelöst wird , wenn es ruft session_startinMage_Core_Model_Session_Abstract_Varien::start

Dies ist zu 100% reproduzierbar. Ich habe die gleiche Methode angewendet, die Sie angewendet haben, indem ich sleep(30)oben ein hinzugefügt habeMage_Adminhtml_IndexController::globalSearchAction

Beachten Sie, dass dies nicht reproduziert werden kann, wenn Sie den Datenbanksitzungsspeicher verwenden. Nachdem ich die Hauptursache gefunden hatte, stellte ich eine Sandbox auf Datenbanksitzungsspeicher ein und konnte das Problem nicht mehr reproduzieren. Die Datenbank-Session-Handler von Magento verwenden anscheinend keine Sperren auf Zeilenebene, um Session-Schreibvorgänge zu sperren. Ich finde das interessant, weil es das Potenzial für Sitzungsdatenverlust gibt, da die Anwendung offensichtlich nicht für mehrere Threads verantwortlich ist, die in dieselbe Sitzung schreiben. Hinweis für Leser: Ich würde in der Produktion niemals db session storage verwenden, um dieses Problem zu lösen. Es ist nur gut, um Ihre MySql-Datenbank zu überlasten.

Ich habe nicht versucht, das Verhalten mit speicherbasierten Sitzungsspeichersystemen wie Redis zu reproduzieren, aber ich vermute, dass das Sperren der Datensätze im Sitzungsspeicher wahrscheinlich auch hier übersehen wurde.

Es gibt Techniken, mit denen dies vermieden werden kann, z. B. session_write_closedas Aufheben der Sperre, bevor Sie einen langfristigen Auftrag ausführen. Dies würde Sie jedoch auch daran hindern, an die Sitzung zu schreiben, da Sie sie gerade geschlossen haben. Es ist daher nicht sehr wahrscheinlich, dass es in Magento allgemein implementiert werden kann, aber es kann möglicherweise auf bestimmten Routen / Controllern implementiert werden.

Meine Technik, um dies als Grundursache festzuhalten, bestand darin, den Xdebug-Profiler zu aktivieren und die "Cachegrind" -Datei zu untersuchen. Sobald die zweite Anforderung abgeschlossen war, lud ich die Ausgabedatei (ca. 25 MB Protokoll) in MacCallGrind und führte einen Drilldown in die Ablaufverfolgung auf dem Pfad der Aufrufe durch, bei denen die Einschlusszeit 28 Sekunden oder mehr betrug. Dies führte mich schließlich zu dem session_startAnruf, dessen Ausführung ~ 28 Sekunden in Anspruch nahm, und gab mir einen großartigen Anhaltspunkt für die Recherche von.

BEARBEITEN: Für die Interessierten habe ich einen Screenshot der "Cachegrind" -Datei gepostet, die in MacCallGrind auf Twitter angezeigt wird.

Davidalger
quelle
Das uRapidFlow-Modul von Unirgy schließt die Sitzung, um dieses in gewisser Weise nette Problem zu vermeiden. Es ist jedoch insofern frustrierend, als es schwierig ist, dem Benutzer anschließend Feedback zu geben.
Peter O'Callaghan
@davidalger - Welchen Sitzungsspeicher verwenden Sie normalerweise für Clientstandorte?
Alan Storm
3
Das erneute Sperren der PHP-Sitzungsdatei beeinträchtigt weniger die Datenintegrität als die Integrität der Datei auf der Festplatte. Wenn mehrere Prozesse geöffnet werden und in Bits auf der Festplatte geschrieben wird (das ist, was eine Datei ist), führt dies schnell zu einer Beschädigung der Daten. MySQL, Redis und die meisten Datenbanken sind so konzipiert, dass sie konsistent bleiben, auch wenn fast gleichzeitig mehrere Schreibvorgänge ausgeführt werden. dh es ist nicht so, dass das Sperren übersehen wurde, es ist so, dass es nicht so dringend benötigt wird.
Alan Storm
@AlanStorm - Eine dedizierte Memcached-Instanz für eine Installation mit Lastenausgleich, Dateisystem für Cluster mit einzelnen Anwendungsknoten. Dateisystem funktioniert am besten, wenn Sie nicht über mehrere Knoten verfügen, da Sie keine IP-Latenz haben.
Davidalger
Richtig, beim Sperren der Datei geht es darum, die Beschädigung von Daten zu verhindern. Wenn Sie die Sperre jedoch halten, bis die Sitzung geschlossen ist, wird ein Datenverlust verhindert. Wenn zwei Prozesse die Sitzungsdaten laden, ändern und dann ausschreiben, werden bei einem von ihnen die Änderungen überschrieben. Dies wird im Allgemeinen kein kritisches Problem darstellen, kann jedoch zu Datenverlust und / oder bösen, schwer zu debuggenden Problemen führen.
Davidalger