web-dev-qa-db-fra.com

E_WARNING: Erreur lors de l'envoi du paquet STMT_PREPARE. PID = *

À compter du 2019-01-30 14:52 UTC, vous pourrez toujours gagner le bonus de 500 points car aucune des réponses ne vous a aidé!

Mon site Web Laravel 5.7 a rencontré quelques problèmes qui, je pense, sont liés les uns aux autres (mais se produisent à des moments différents):

  1. PDO::prepare(): MySQL server has gone away
  2. E_WARNING: Error while sending STMT_PREPARE packet. PID=10
  3. PDOException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry (Ma base de données semble souvent essayer d'écrire le même enregistrement deux fois dans la même seconde. Je ne suis pas parvenu à comprendre pourquoi ni comment le reproduire; cela ne semble pas être lié au comportement de l'utilisateur.)
  4. D'une manière ou d'une autre, ces 2 premiers types d'erreurs n'apparaissent que dans les journaux de mon Rollbar, mais pas dans les journaux de texte sur le serveur ni dans mes notifications Slack, car toutes les erreurs sont supposées (et tous les autres le sont).

Pendant des mois, j'ai continué à voir des messages de journal effrayants comme ceux-ci, et je suis complètement incapable de reproduire ces erreurs (et j'ai été incapable de les diagnostiquer et de les résoudre).

Je n'ai pas encore trouvé de symptômes réels ni entendu de plaintes de la part des utilisateurs, mais les messages d'erreur ne sont pas anodins, je souhaite donc comprendre et corriger les causes profondes.


J'ai essayé de changer ma configuration MySQL pour utiliser max_allowed_packet=300M (au lieu de default de 4M), mais j'ai toujours ces exceptions fréquemment les jours où j'ai plus de deux visiteurs sur mon site.

J'ai également défini (changé de 5M et 10M) le suivant à cause de ce conseil :

innodb_buffer_pool_chunk_size=218M
innodb_buffer_pool_size = 218M

Comme arrière-plan:

  • Mon site dispose d'un programme de travail en file d'attente qui exécute des travaux (artisan queue:work --sleep=3 --tries=3 --daemon).
  • De nombreuses tâches en file d'attente peuvent être planifiées au même moment, en fonction de l'heure d'inscription des visiteurs. Mais tout ce que je vois qui se sont produits simultanément est de 20.
  • Le journal des requêtes lentes de MySQL ne contient aucune entrée.
  • J'ai quelques emplois clairs, mais je doute qu'ils posent problème. On court toutes les minutes mais c'est vraiment simple. Une autre s'exécute toutes les 5 minutes pour envoyer certains courriels planifiés, le cas échéant. Et un autre s'exécute toutes les 30 minutes pour générer un rapport.
  • J'ai lancé diverses requêtes mysqlslap (je suis tout à fait novice) et je n'ai rien trouvé de lent, même lors de la simulation de centaines de clients simultanés.
  • J'utilise Laradock (Docker).
  • Mon serveur est DigitalOcean 1 Go de RAM, 1 vCPU, 25 Go SSD. J'ai également essayé 2 Go RAM sans aucune différence.
  • Les résultats de SHOW VARIABLES; et SHOW GLOBAL STATUS;sont ici .

Mon my.cnf est:

[mysql]

[mysqld]
sql-mode="STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION"
character-set-server=utf8
innodb_buffer_pool_chunk_size=218M
innodb_buffer_pool_size = 218M
max_allowed_packet=300M
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow_query_log.log
long_query_time = 10
log_queries_not_using_indexes = 0

Des idées sur ce que je devrais explorer pour diagnostiquer et résoudre ces problèmes? Merci.


10
Ryan

Re Slowlog: Montrez-nous votre my.cnf. Les modifications ont-elles été apportées dans la section [mysqld]? Testez-le via SELECT SLEEP(12);, puis examinez le fichier et le tableau.

Autre moyen de trouver la requête: Comme la requête prend plusieurs minutes, faites SHOW FULL PROCESSLIST; lorsque vous pensez qu'elle est peut-être en cours d'exécution.

Combien RAM avez-vous? Est-ce que pas a max_allowed_packet=300M sauf si vous avez au moins 30 Go de RAM? Sinon, vous risquez de permuter (ou même de vous écraser). Gardez ce paramètre sous 1% de RAM.

Pour une analyse plus approfondie des paramètres ajustables, veuillez fournir (1) RAM taille, (2) SHOW VARIABLES; et (3) SHOW GLOBAL STATUS;.

Re deleted_at: Le lien que vous avez donné commence par "La colonne delete_at n’est pas un bon candidat pour l’index". Vous l'avez mal interprété. Il s'agit d'une INDEX(deleted_at) à une colonne. Je suggère un indice composite tel que INDEX(contact_id, job_class_name, execute_at, deleted_at).

158 secondes pour une requête simple sur une petite table? Il se peut qu'il y ait beaucoup de autres choses en cours. Obtenez la PROCESSLIST.

Re Indices séparés par rapport aux composites: Pensez à deux index: INDEX(last_name) et INDEX(first_name). Vous parcourez l'index last_name pour trouver "James", que pouvez-vous faire? Parcourir l'autre index pour "Rick" ne vous aidera pas à me trouver.

Analyse des variables et du statut global

Observations:

  • Version: 5.7.22-log
  • 1,00 Go de RAM
  • Disponibilité = 16d 10:30:19
  • Etes-vous sûr que c'était un SHOW GLOBAL STATUS?
  • Vous n'utilisez pas Windows.
  • Exécution de la version 64 bits
  • Vous semblez utiliser entièrement (ou principalement) InnoDB.

Les questions les plus importantes:

innodb_buffer_pool_size - Je pensais que vous l’aviez à 213M, pas à 10M. 10M est beaucoup trop petit. D'autre part, vous semblez avoir moins de données que cela.

Etant donné que RAM est si petit, je vous recommande de supprimer tmp_table_size et max_heap_table_size et max_allowed_packet à 8M .

Quelles sont les causes de tant de connexions simultanées?

Détails et autres observations:

( innodb_buffer_pool_size / _ram ) = 10M / 1024M = 0.98% -% of RAM utilisé pour InnoDB buffer_pool

( innodb_buffer_pool_size ) = 10M - Cache InnoDB Data + Index

( innodb_lru_scan_depth ) = 1,024-- "InnoDB: page_cleaner: la boucle prévue de 1000 ms a été prise ..." peut être corrigé en abaissant lru_scan_depth

( Innodb_buffer_pool_pages_free / Innodb_buffer_pool_pages_total ) = 375 / 638 = 58.8% - Pct de buffer_pool non utilisé actuellement -- innodb_buffer_pool_size est plus grand que nécessaire?

( Innodb_buffer_pool_bytes_data / innodb_buffer_pool_size ) = 4M / 10M = 40.0% - Pourcentage du pool de mémoire tampon occupé par les données -- Un petit pourcentage peut indique que le pool de tampons est inutilement grand.

( innodb_log_buffer_size / _ram ) = 16M / 1024M = 1.6% - Pourcentage de RAM utilisé pour la mise en tampon des écritures de journaux InnoDB .-- Trop grande enlève d'autres utilisations de la RAM.

( innodb_log_file_size * innodb_log_files_in_group / innodb_buffer_pool_size ) = 48M * 2 / 10M = 960.0% - Rapport entre la taille du journal et la taille de buffer_pool. Il est recommandé 50%, mais consultez les autres calculs pour savoir si cela est important .-- Il n'est pas nécessaire que le journal soit plus volumineux que le pool de mémoire tampon.

( innodb_flush_method ) = innodb_flush_method = - Comment InnoDB devrait-il demander au système d'exploitation d'écrire des blocs. Suggérez O_DIRECT ou O_ALL_DIRECT (Percona) pour éviter la double mise en mémoire tampon. (Au moins pour Unix.) Voir chrischandler pour l'avertissement à propos de O_ALL_DIRECT

( innodb_flush_neighbors ) = 1 - Une optimisation mineure lors de l'écriture de blocs sur le disque .-- Utilisez 0 pour les lecteurs SSD; 1 pour le disque dur.

( innodb_io_capacity ) = 200 - Capacité d'E/S par seconde sur le disque. 100 pour les lecteurs lents; 200 pour la filature; 1000-2000 pour les SSD; multiplier par le facteur RAID.

( innodb_print_all_deadlocks ) = innodb_print_all_deadlocks = OFF - S'il faut enregistrer tous les deadlocks .-- Si vous êtes en proie à des deadlocks, activez cette option. Attention: Si vous avez beaucoup de blocages, cela peut en écrire beaucoup sur le disque.

( min( tmp_table_size, max_heap_table_size ) / _ram ) = min( 16M, 16M ) / 1024M = 1.6% - Pourcentage de RAM à allouer lorsque vous avez besoin d'une table MEMORY (par table) ou d'une table temporaire dans un SELECT (par table temporaire pour certains SELECT). Trop élevé peut conduire à un échange .-- Réduisez tmp_table_size et max_heap_table_size à, par exemple, 1% de la RAM.

( net_buffer_length / max_allowed_packet ) = 16,384 / 16M = 0.10%

( local_infile ) = local_infile = ON-- local_infile = ON est un problème de sécurité potentiel

( Select_scan / Com_select ) = 111,324 / 264144 = 42.1% -% des personnes sélectionnées effectuent une analyse complète de la table. (Peut être dupé par les routines stockées.) -- Ajouter des index/optimiser des requêtes

( long_query_time ) = 10 - Cutoff (Seconds) pour définir une requête "lente" .-- Suggérer 2

( Max_used_connections / max_connections ) = 152 / 151 = 100.7% -% maximum de connexions -- augmenter max_connections et/ou diminuer wait_timeout

Vous avez le cache de requêtes à moitié éteint. Vous devez définir query_cache_type = OFF et query_cache_size = 0. Selon la rumeur, il existe un «bogue» dans le code de contrôle de la qualité qui laisse du code activé sauf si vous désactivez ces deux paramètres.

Anormalement petit:

( Innodb_pages_read + Innodb_pages_written ) / Uptime = 0.186
Created_tmp_files = 0.015 /HR
Handler_write = 0.21 /sec
Innodb_buffer_pool_bytes_data = 3 /sec
Innodb_buffer_pool_pages_data = 256
Innodb_buffer_pool_pages_total = 638
Key_reads+Key_writes + Innodb_pages_read+Innodb_pages_written+Innodb_dblwr_writes+Innodb_buffer_pool_pages_flushed = 0.25 /sec
Table_locks_immediate = 2.8 /HR
Table_open_cache_hits = 0.44 /sec
innodb_buffer_pool_chunk_size = 5MB

Anormalement grand:

Com_create_db = 0.41 /HR
Com_drop_db = 0.41 /HR
Connection_errors_peer_address = 2
Performance_schema_file_instances_lost = 9
Ssl_default_timeout = 500

Chaînes anormales:

ft_boolean_syntax = + -><()~*:&
have_ssl = YES
have_symlink = DISABLED
innodb_fast_shutdown = 1
optimizer_trace = enabled=off,one_line=off
optimizer_trace_features = greedy_search=on, range_optimizer=on, dynamic_range=on, repeated_subselect=on
session_track_system_variables = time_zone, autocommit, character_set_client, character_set_results, character_set_connection
slave_rows_search_algorithms = TABLE_SCAN,INDEX_SCAN
4
Rick James

Si vous voyez ce message au hasard, raisons possibles:

  1. Votre MySQL est derrière un proxy, et ils utilisent une configuration timeout différente. 

  2. Vous utilisez la connexion persistante de PHP.

Vous pouvez essayer de creuser le problème en procédant comme suit:

  1. Assurez-vous que vos connexions à MySQL ont un délai d’expiration suffisamment long (par exemple: paramètre de proxy, wait_timeout/interactive_timeout de MySQL)

  2. Désactivez la connexion persistante du côté PHP.

  3. Faites un tcpdump si vous pouvez voir ce qui s’est passé lorsque vous avez reçu le message d’erreur.

0
shawn