Comment puis-je configurer MySQL Innodb pour gérer des milliers d'insertions par heure?

10

J'ai un site Web très fréquenté où il est possible que des milliers de nouveaux enregistrements soient insérés toutes les heures.

Cette seule erreur paralyse le 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 )

Je serais très surpris si MySQL ne pouvait pas gérer ce type de charge. Donc, mes questions sont alors, est-ce un problème de base de données et comment puis-je configurer MySQL pour pouvoir gérer autant de trafic?

J'ai une copie de mon site Web installée sur un serveur de développement avec des scripts qui simulent la charge de contenu ajoutée au site Web. J'utilise Ubuntu, pile LAMP, avec 16 Go de RAM.

Certes, je ne connais pas très bien les bases de données. En fait, je commence avec le fichier my.cnf par défaut qui l'accompagne après la fin de «apt-get install». Les tables sont toutes Innodb. Quels paramètres de configuration et quelle approche recommanderiez-vous pour commencer à résoudre ce problème?

Faites-moi savoir de plus amples informations dont vous pourriez avoir besoin.

Merci

user658182
la source
Vous commencez avec le fichier my.cnf par défaut pour la production? Mec, tu dois l'optimiser davantage. Vous détaillera plus dans ma réponse. :-)

Réponses:

11

Vous avez affaire à un blocage, pas à un problème de goulot d'étranglement des performances.

Si vous avez un millier de nouveaux enregistrements par heure, vous êtes loin de pouvoir atteindre les limites de MySQL. MySQL peut gérer au moins 50 fois votre charge.

Les interblocages sont dus au code d'application et ne sont pas la faute du serveur de base de données. Les blocages ne peuvent pas être corrigés côté serveur MySQL, sauf dans certaines situations spécifiques.

InnoDBpeut vous montrer des informations détaillées sur les blocages en exécutant SHOW ENGINE INNODB STATUSà l'invite MySQL ou avec mysql -uroot -p... -e "SHOW ENGINE INNODB STATUS".

Cependant, cela ne montre que le dernier blocage qui s'est produit, il n'y a pas de journal de blocage.

Heureusement, il existe un outil pt-deadlock-logger qui s'occupe de ce problème, il prend en charge l'état d'interrogation InnoDBet enregistre toutes les informations détaillées sur les interblocages avant qu'il ne soit actualisé avec un nouveau blocage.

Valeur
la source
Bon à savoir! Je vois dans la commande show status les informations sur le verrou et la requête et la table associées. Étant donné que cela se trouve dans mon code, comment puis-je utiliser ces informations de la commande status pour commencer à déboguer le problème? La requête PHP PDO est assez simple - connectez, préparez, exécutez, répétez. Je serais heureux de publier n'importe quel code ou le message d'état si cela pouvait aider.
user658182
@ user658182 consultez ce post sur stackoverflow sur la façon de gérer les blocages: comment éviter le blocage mysql trouvé lors de la tentative de verrouillage
Valor
1
@ max-vernon merci pour la modification de la syntaxe, clairement l'anglais ce n'est pas ma langue maternelle :-).
Valor
1
-e "AFFICHER LE STATUT DU MOTEUR INNODB"
glyphe
8

Cela peut être aussi simple qu'une partie de votre code exécutant une transaction:

insert into t1...
insert into t2...
commit;

tandis qu'une autre partie de votre code modifie les mêmes tables dans un ordre différent:

delete from t2 where...
delete from t1 where...
commit;

Si ces deux transactions s'exécutent en même temps, une condition de concurrence critique peut se produire: la première transaction ne peut pas être modifiée t2car elle est verrouillée par la deuxième transaction; tandis que la deuxième transaction est également bloquée car elle t1est verrouillée par la première transaction. MySQL choisit une transaction pour être la "victime" où INSERT / UPDATE / DELETE échoue. L'application doit intercepter cette erreur et réessayer l'instruction - peut-être après une pause pour que l'autre transaction ait le temps de se terminer. Rien à voir avec les limites de capacité, juste un timing malheureux qui peut être exacerbé par la façon dont le code est organisé. Basculez les DELETEs dans la transaction # 2 ou les INSERTs dans la transaction # 1, puis il n'y a pas de conflit - chaque transaction attendra l'accès aux tables dont elle a besoin.

Dans MySQL 5.6, vous pouvez exécuter avec l' option innodb_print_all_deadlocks activée pour collecter des informations sur tous les blocages (pas seulement le plus récent) dans le journal des erreurs MySQL.

[Clause de non-responsabilité obligatoire: je suis un employé d'Oracle. Ce qui précède est mon avis personnel et non une déclaration officielle.]

Max Webster
la source