Ich habe ein Problem, bei dem der Prozess der erneuten Indizierung des Produktpreises meines Erachtens eine Deadlock-Ausnahme im Checkout-Prozess verursacht.
Ich habe diese Ausnahme beim Auschecken festgestellt:
Ausnahme bei der Auftragskonvertierung: SQLSTATE [40001]: Serialisierungsfehler: 1213 Deadlock beim Versuch, eine Sperre abzurufen; Starten Sie die Transaktion erneut
Leider habe ich keinen vollständigen Stack-Trace, da die Ausnahme abgefangen wurde, aber ich habe den INNODB-Status überprüft und konnte den Deadlock aufspüren:
SELECT `si`.*, `p`.`type_id` FROM `cataloginventory_stock_item` AS `si`
INNER JOIN `catalog_product_entity` AS `p` ON p.entity_id=si.product_id
WHERE (stock_id=1)
AND (product_id IN(47447, 56678)) FOR UPDATE
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 329624 n bits 352 index
`PRIMARY` of table `xxxx`.`catalog_product_entity`
Die SQL-Anfragetabellensperre wird letztendlich generiert, Mage_CatalogInventory_Model_Stock::registerProductsSale()
wenn versucht wird, die aktuelle Inventurzählung abzurufen, um sie zu dekrementieren.
Zu dem Zeitpunkt, als der Deadlock auftrat, wurde der Produktpreis-Neuindexierungsprozess ausgeführt, und ich gehe davon aus, dass er eine Lesesperre für die hatte catalog_product_entity table
, die den Deadlock verursacht hat. Wenn ich den Deadlock richtig verstehe, wird durch jede Lesesperre ein Deadlock ausgelöst, aber der Produktpreis-Neuindex hält die Sperre für eine angemessene Zeit aufrecht, da auf der Site ~ 50.000 Produkte vorhanden sind.
Leider wurde zu diesem Zeitpunkt im Bestellcode-Fluss die Kreditkarte des Kunden belastet (über ein benutzerdefiniertes Zahlungsmodul), und die Erstellung des entsprechenden Bestellobjekts schlug fehl.
Meine Fragen sind:
- Ist die Logik des benutzerdefinierten Zahlungsmoduls fehlerhaft? Dh Gibt es einen akzeptierten Ablauf, um sicherzustellen, dass Magento das Angebot in eine Bestellungsausnahme umwandeln kann, bevor die Belastung der Zahlungsmethode (Kreditkarte) zugewiesen wird?
Bearbeiten: Es scheint, dass die Logik des Zahlungsmoduls tatsächlich fehlerhaft ist, da der Aufruf von $ paymentmethod-> authorize () nach dem Ort erfolgen sollte, an dem dieser Deadlock auftritt, und nicht vorher (wie in der Antwort von Ivan unten angegeben). Die Transaktion wird jedoch weiterhin durch den Deadlock blockiert (allerdings ohne die fehlerhafte Belastung der Kreditkarte).
Dieser Funktionsaufruf
$stockInfo = $this->_getResource()->getProductsStock($this, array_keys($qtys), true);
inMage_CatalogInventory_Model_Stock::registerProductsSale()
macht es zu einem Sperr lesen, wie gefährlich es wäre es ein nicht sperr gelesen werden , um zu machen?Beim Durchsuchen des Webs nach einer Antwort haben einige Stellen vorgeschlagen, keine vollständige Neuindizierung durchzuführen, solange die Site noch in Betrieb ist. scheint kaum eine gute Lösung zu sein; Ist das Problem der Indizierung, das zu Tabellen-Deadlocks und Sperrenkonflikten führt, in Magento ein bekanntes Problem? Gibt es Problemumgehungen?
Bearbeiten: Es scheint, die verbleibende Frage hier ist die aus der dritten Frage; Neuindizierung führt zu Table Deadlocks. Suchen Sie nach Problemumgehungen dafür.
Bearbeiten: Das Konzept, dass Deadlocks nicht an sich Probleme sind, sondern die Reaktion auf sie im Mittelpunkt stehen sollte, ist sehr sinnvoll. Weitere Untersuchungen, um einen Punkt im Code zu finden, um die Deadlock-Ausnahme abzufangen und die Anforderung erneut auszustellen. Dies auf der Ebene des Zend Framework DB-Adapters zu tun, ist ein Ansatz, aber ich suche auch nach einer Möglichkeit, dies im Magento-Code zu tun, um die Wartbarkeit zu vereinfachen.
Es gibt einen interessanten Patch in diesem Thread: http://www.magentocommerce.com/boards/viewthread/31666/P0/ , der eine damit verbundene Deadlock-Bedingung zu lösen scheint (aber nicht diese speziell).
Edit: Anscheinend wurde Deadlocking bis zu einem gewissen Grad in CE 1.8 Alpha behoben. Suchen Sie noch nach einer Problemumgehung, bis diese Version von Alpha ist
Antworten:
Es ist sehr wahrscheinlich, dass Ihre Zahlungsmethode die Zahlung falsch verarbeitet.
Das Speichern von Magento-Bestellungen ist ganz einfach:
checkout_type_onepage_save_order
und senden Siesales_model_service_quote_submit_before
Mage_CatalogInventory_Model_Stock::registerProductsSale()
wird bei diesem Ereignisbeobachter aufgerufen$order->place()
Methode, die die Zahlung durch den Aufruf verarbeitet$paymentMethod->authorize()
,$paymentMethod->capture()
oder$paymentMethod->initialize()
hängt von seiner Logik.sales_flat_order_*
.Wie Sie sehen, könnte es nicht möglich sein, dass die Zahlungsmethode vor dem Sperren des Lagerbestands Geld belastet und Produktpreise oder Produktinformationen liest.
Es ist nur möglich, wenn die Zahlungsmethode so implementiert ist, dass sie das Laden von Produkten selbst mit Preisen durchführt, nachdem der API-Aufruf für den Ladevorgang ausgeführt wurde.
Hoffe, dies wird Ihnen beim Debuggen Ihres Problems helfen.
Was die Neuindizierung angeht, sollte es sicher sein, wenn Sie dieses Problem mit der Zahlungsmethode nicht haben. Da Lesevorgänge, die von Sperren abhängen, ausgeführt werden, bevor Geld belastet wird.
quelle
registerProductsSale()
auslöst.Da es sich um eine benutzerdefinierte Erweiterung handelt, können wir eine benutzerdefinierte Problemumgehung (read: hack) finden, um das Speichern erneut zu versuchen, ohne die Kerndateien zu bearbeiten.
Ich habe alle meine Deadlock-Probleme mit den folgenden zwei Methoden gelöst, die einer Helferklasse hinzugefügt wurden. Anstatt
$product->save()
anzurufen, rufe ich jetzt anMage::helper('mymodule')->saferSave($product)
:Dadurch werden zwei verschiedene Dinge erreicht: Es wird eine Wiederholung in die Warteschlange gestellt, wenn ein Deadlock auftritt, und es wird ein exponentiell ansteigendes Zeitlimit für diese Wiederholung festgelegt. Außerdem wird die Transaktionsisolationsstufe festgelegt. Es gibt viele Informationen zu SO und DBA.SE, um weitere Informationen zu den Transaktionsisolationsstufen von MySQL zu erhalten.
FWIW, seitdem bin ich keinem Deadlock mehr begegnet.
quelle
$tries
diese Funktion zu übergebensleep($this->getDelay());
In den Magento-Foren wird über das Bearbeiten einer Zend-Bibliotheksdatei gesprochen: lib / Zend / Db / Statement / Pdo.php
Die ursprüngliche Funktion _execute:
Nach der Modifikation:
Wie Sie sehen können, wurde nur geändert, dass die $ try außerhalb der Schleife verschoben wurden.
Wie immer wird empfohlen, dies in einer Entwicklungs- / Testumgebung auszuprobieren und diesen Fix nicht sofort in einer Produktionsumgebung bereitzustellen.
quelle
Ich habe das gleiche Problem auf einer Magento 1.11-Site und habe seit dem 12.11.2012 ein offenes Ticket mit Magento. Sie haben bestätigt, dass es sich um ein Problem handelt, und es wird angenommen, dass sie einen Patch erstellen.
Meine Frage ist, warum der Preis zu diesem Zeitpunkt neu indiziert werden muss. Ich denke nicht, dass das nötig ist:
quelle
Wir hatten ein ähnliches Deadlock-Problem, als bestimmte Aufrufe während einer Neuindizierung getätigt wurden. Für uns zeigte es sich meistens, wenn ein Kunde etwas in den Warenkorb legen würde. Obwohl das eigentliche zugrunde liegende Problem wahrscheinlich nicht behoben wurde, hat die Implementierung einer asynchronen Neuindizierung alle zuvor aufgetretenen Deadlock-Aufrufe vollständig gestoppt. Sollte eine Lücke schließen, bis das zugrunde liegende Problem behoben und auf die EE / CE-Editionen verschoben wurde (wir haben uns dafür eine Erweiterung gekauft).
quelle
Ich schlage vor, dass Sie Philwinkle DeadlockRetry installieren. Es funktionierte für unsere Datenbank.
Ich würde auch vorschlagen, Ihre externen Programme zu betrachten, die auf Ihre Web-API treffen. Wir hatten eine, die die Menge der Produkte aktualisierte und viele Deadlocks verursachte. Wir haben das umgeschrieben und sind direkt zur Datenbank gegangen.
quelle
Ich bin letztes Jahr mehrfach auf ein Deadlock-Problem gestoßen und habe es einfach durch Erhöhen des Speichers für unseren Server behoben, da der Indizierungsprozess alle Ressourcen verschlingt.
Sie sollten auch uns asynchrone Reindex-Lösung verwenden, die ich miravist
Für ein stabileres System sollten Sie daran denken, Ihr Backend vom Frontend zu trennen, damit sie nicht gegenseitig den Arbeitsspeicher belasten.
Nach meiner Erfahrung ist es kein Problem des Quellcodes.
quelle