42 votes

"Le serveur MySQL a disparu" avec Ruby on Rails

Après que notre application Ruby on Rails ait fonctionné pendant un certain temps, elle commence à envoyer des messages 500 avec le message "MySQL server has gone away". Cela se produit souvent pendant la nuit. Il a commencé à le faire récemment, sans changement évident dans la configuration de notre serveur.

 Mysql::Error: MySQL server has gone away: SELECT * FROM `widgets`

Le redémarrage des bâtonnets (pas du serveur MySQL) résout le problème.

Comment pouvons-nous régler ce problème ?

61voto

mixonic Points 1981

Ruby on Rails 2.3 dispose d'une option de reconnexion pour votre connexion à la base de données :

production:
  # Your settings
  reconnect: true

Voir :

Bonne chance !

22voto

Laurie Young Points 37065

Cela est probablement dû à la disparition des connexions persistantes à MySQL (un dépassement de délai est probable si cela se produit la nuit) et au fait que Ruby on Rails ne parvient pas à rétablir la connexion, ce qu'il devrait faire par défaut :

Le code se trouve dans le fichier vendor/rails/actionpack/lib/action_controller/dispatcher.rb :

if defined?(ActiveRecord)
  before_dispatch { ActiveRecord::Base.verify_active_connections! }
  to_prepare(:activerecord_instantiate_observers) {ActiveRecord::Base.instantiate_observers }
end

La méthode verify_active_connections! effectue plusieurs actions, dont l'une consiste à recréer toutes les connexions expirées.

La cause la plus probable de cette erreur est que c'est parce qu'une carré de singe a redéfini le répartiteur pour ne pas appeler verify_active_connections! ou verify_active_connections! a été modifié, etc.

2 votes

Ouais ; j'ai passé le problème en attrapant ActiveRecord::StatementInvalid une fois et en appelant manuellement ActiveRecord::Base.verify_active_connections! quand je suis tombé sur ça.

0 votes

@Conny, où est-ce que ActiveRecord::StatementInvalid aller ? dans application_controller.rb ? Ou ailleurs ?

1 votes

@ChristianFazzini, c'était à l'intérieur d'un démon autonome qui servait un objectif spécifique à l'application : je n'ai jamais eu ce problème à l'intérieur d'une vieille application web Rails. Si c'était le cas, j'utiliserais maintenant Rails 2.3 ou une version plus récente et j'utiliserais l'option de reconnexion. comme proposé par mixonic

4voto

Dave Cheney Points 2195

Comme l'ont dit les autres contributeurs à ce fil de discussion, il est très probable que le serveur MySQL ait fermé la connexion à votre application Ruby on Rails pour cause d'inactivité. Le délai d'attente par défaut est de 28800 secondes, soit 8 heures.

set-variable = wait_timeout=86400

En ajoutant cette ligne à votre /etc/my.cnf portera le délai d'attente à 24 heures http://dev.mysql.com/doc/refman/5.0/en/server-system-variables.html#option_mysqld_wait_timeout .

Bien que la documentation ne l'indique pas, une valeur de 0 mai désactiver complètement le délai d'attente, mais vous devez expérimenter car ce ne sont que des spéculations.

Il y a cependant trois autres situations que je connais qui peuvent générer cette erreur. La première est le redémarrage du serveur MySQL. Cela entraîne évidemment la perte de toutes les connexions, mais comme le client MySQL est passif, vous ne le remarquerez pas avant d'effectuer la prochaine requête.

La deuxième condition est que quelqu'un tue votre requête à partir de la ligne de commande MySQL, et cela coupe également la connexion, car cela pourrait laisser le client dans un état indéfini.

Le dernier cas est celui où votre serveur MySQL redémarre lui-même en raison d'une erreur interne fatale. En d'autres termes, si vous effectuez une simple requête sur une table et que vous voyez instantanément "MySQL a disparu", j'examinerais attentivement les journaux de votre serveur pour vérifier s'il y a une erreur matérielle ou une corruption de la base de données.

0 votes

Dans les applications rails sur lesquelles j'ai travaillé, je n'ai pas vu Active Record se reconnecter pendant la requête en cours, mais il se reconnecte à la requête suivante, donc cela peut être une condition temporaire si vous pouvez copier une exception par bâtard.

2voto

Abdo Points 3360

Tout d'abord, déterminez le max_connections dans MySQL :

show variables like "max_connections";

Vous devez vous assurer que le nombre de connexions que vous effectuez dans votre application Ruby on Rails est inférieur au nombre maximal de connexions autorisé. Notez que les connexions supplémentaires peuvent provenir de votre cron jobs, les processus delayed_job (chacun d'entre eux aurait la même taille de pool dans vos database.yml ), etc.

Surveillez les connexions SQL au fur et à mesure de votre application, de l'exécution des processus, etc. en effectuant les opérations suivantes dans MySQL :

show status where variable_name = 'Threads_connected';

Vous pouvez envisager de fermer les connexions après un Thread termine l'exécution car les connexions aux bases de données ne sont pas fermées automatiquement (je pense que ce problème se pose moins avec les applications Ruby on Rails 4) Faucheur ) :

Thread.new do
  begin
     # Thread work here
  ensure
     begin
        if (ActiveRecord::Base.connection && ActiveRecord::Base.connection.active?)
           ActiveRecord::Base.connection.close
        end
      rescue
      end
  end
end

1voto

David Precious Points 4429

La connexion au serveur MySQL est probablement interrompue.

Vous devriez être en mesure d'augmenter le délai d'attente dans MySQL, mais pour une correction correcte, demandez à votre code de vérifier que la connexion à la base de données est toujours active, et de se reconnecter si elle ne l'est pas.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X