Ich habe eine sehr stark frequentierte Website, auf der möglicherweise jede Stunde Tausende neuer Datensätze eingefügt werden.
Dieser eine Fehler lähmt die Site:
PDOException: SQLSTATE[40001]: Serialization failure: 1213
Deadlock found when trying to get lock;
try restarting transaction: INSERT INTO {location_instance}
(nid, vid, uid, genid, lid) VALUES (:db_insert_placeholder_0,
:db_insert_placeholder_1, :db_insert_placeholder_2,
:db_insert_placeholder_3, :db_insert_placeholder_4);
Array ( [:db_insert_placeholder_0] => 1059 [:db_insert_placeholder_1] =>
1059 [:db_insert_placeholder_2] => 0 [:db_insert_placeholder_3] =>
cck:field_item_location:1059 [:db_insert_placeholder_4] => 1000 )
Ich wäre sehr überrascht, wenn MySQL diese Art von Last nicht bewältigen könnte. Meine Fragen sind also: Ist dies ein Datenbankproblem und wie kann ich MySQL so konfigurieren, dass es so viel Verkehr verarbeiten kann?
Ich habe eine Kopie meiner Website auf einem Entwicklungsserver mit Skripten eingerichtet, die das Laden von Inhalten simulieren, die der Website hinzugefügt werden. Ich verwende Ubuntu, LAMP-Stack, mit 16 GB RAM.
Zugegeben, ich kenne mich mit Datenbanken nicht sehr gut aus. Tatsächlich beginne ich mit der Standardeinstellung my.cnf, die nach Abschluss der 'apt-get-Installation' mitgeliefert wird. Tische sind alle Innodb. Welche Startkonfigurationseinstellungen und -ansätze würden Sie empfehlen, um dieses Problem zu lösen?
Lassen Sie mich wissen, welche weiteren Informationen Sie möglicherweise benötigen.
Vielen Dank
Antworten:
Sie haben es mit einem Deadlock zu tun, nicht mit einem Leistungsengpass.
Wenn Sie tausend neue Datensätze pro Stunde haben, sind Sie weit davon entfernt, die MySQL-Grenzen zu erreichen. MySQL kann mindestens das 50-fache Ihrer Last verarbeiten.
Deadlocks werden durch den Anwendungscode verursacht und sind nicht die Schuld des Datenbankservers. Deadlocks können auf der MySQL-Serverseite nur in bestimmten Situationen behoben werden.
InnoDB
kann Ihnen detaillierte Deadlock-Informationen anzeigen, indem SieSHOW ENGINE INNODB STATUS
an der MySQL-Eingabeaufforderung oder mit ausführenmysql -uroot -p... -e "SHOW ENGINE INNODB STATUS"
.Dies zeigt jedoch nur den letzten aufgetretenen Deadlock an, es gibt kein Deadlock-Protokoll.
Zum Glück gibt es ein Tool pt-deadlock-logger, das sich um dieses Problem kümmert, sich um den Abfragestatus kümmert
InnoDB
und alle detaillierten Deadlock-Informationen speichert, bevor es mit einem neuen Deadlock aktualisiert wird.quelle
Dies kann so einfach sein wie ein Teil Ihres Codes, der eine Transaktion ausführt:
Während ein anderer Teil Ihres Codes dieselben Tabellen in einer anderen Reihenfolge ändert:
Wenn beide Transaktionen gleichzeitig ausgeführt werden, kann eine Race-Bedingung auftreten: Die erste Transaktion kann nicht geändert werden,
t2
da sie von der zweiten Transaktion gesperrt wird. während die zweite Transaktion ähnlich blockiert ist, weilt1
sie von der ersten Transaktion gesperrt wird. MySQL wählt eine Transaktion als "Opfer" aus, bei dem INSERT / UPDATE / DELETE fehlschlägt. Die Anwendung muss diesen Fehler abfangen und die Anweisung erneut versuchen - möglicherweise nach einer Pause, damit die andere Transaktion Zeit zum Abschluss hat. Nichts mit Kapazitätsbeschränkungen zu tun, nur unglückliches Timing, das durch die Anordnung des Codes noch verschärft werden kann. Schalten Sie die DELETEs in Transaktion 2 oder die INSERTs in Transaktion 1 um, und dann liegt kein Konflikt vor. Jede Transaktion wartet auf den Zugriff auf die benötigten Tabellen.In MySQL 5.6 können Sie mit aktivierter Option innodb_print_all_deadlocks ausführen , um Informationen zu allen Deadlocks (nicht nur zu den neuesten) im MySQL-Fehlerprotokoll zu sammeln.
[Obligatorischer Haftungsausschluss: Ich bin ein Oracle-Mitarbeiter. Das Obige ist meiner persönlichen Ansicht nach keine offizielle Aussage.]
quelle