it-swarm-eu.dev

"MySQL server je pryč" s Ruby on Rails

Poté, co naše aplikace Ruby on Rails běží nějakou dobu, začne házet 500s s "MySQL serverem pryč". Často k tomu dochází přes noc. To začalo dělat nedávno, bez zjevné změny v konfiguraci serveru.

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

Restartování mongrels (ne MySQL server) to opravuje.

Jak to můžeme opravit?

38
Gwyn Morfey

To je pravděpodobně způsobeno trvalým připojením k MySQL pryč (časový limit je pravděpodobný, pokud se to děje přes noc) a Ruby on Rails nedokáže obnovit spojení, které by mělo ve výchozím nastavení provádět:

V souboru dodavatele/Rails/actionpack/lib/action_controller/dispatcher.rb je kód:

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

Metoda verify_active_connections! provádí několik akcí, z nichž jednou je znovu vytvořit všechna vypršená připojení.

Nejpravděpodobnější příčinou této chyby je, že je to proto, že a patch pro opici předefinoval dispečera, který nemá volat verify_active_connections!, nebo verify_active_connections! byl změněn, atd.

22
Laurie Young

Ruby on Rails 2.3 má možnost obnovení připojení k databázi:

production:
  # Your settings
  reconnect: true

Vidět:

Hodně štěstí!

61
mixonic

Jak řekli ostatní přispěvatelé tohoto vlákna, je nejpravděpodobnější, že MySQL server ukončil spojení s vaší aplikací Ruby on Rails z důvodu nečinnosti. Výchozí časový limit je 28800 sekund nebo 8 hodin. 

set-variable = wait_timeout=86400

Přidání tohoto řádku do /etc/my.cnf zvýší časový limit na 24 hodin http://dev.mysql.com/doc/refman/5.0/en/server-system-variables.html#option_mysqld_wait_timeout .

I když to dokumentace neznamená, hodnota 0 může vypnout časový limit úplně, ale budete muset experimentovat, protože to je jen spekulace.

Existují však tři další situace, o nichž vím, že mohou generovat tuto chybu. První je restartování serveru MySQL. To bude samozřejmě pokles všech spojení, ale jako klient MySQL je pasivní, a to nebude všiml, dokud si další dotaz.

Druhou podmínkou je, pokud někdo zabije váš dotaz z příkazového řádku MySQL, a to také upustí spojení, protože by to mohlo zanechat klienta v nedefinovaném stavu.

Poslední je, pokud se váš MySQL server restartuje kvůli fatální vnitřní chybě. To znamená, že pokud děláte jednoduchý dotaz proti tabulce a okamžitě zjistíte, že MySQL odejde, podrobně bych se podíval na protokoly vašeho serveru, abych zkontroloval chybu hardwaru nebo poškození databáze.

4
Dave Cheney

Měl jsem tento problém, když posílám do MySQL opravdu velké prohlášení. MySQL omezuje velikost výpisů a uzavře spojení, pokud překročíte limit.

set global max_allowed_packet = 1048576; # 2^20 bytes (1 MB) was enough in my case
2
Isaac Betesh

Vyzkoušejte ActiveRecord::Base.connection.verify! v Ruby on Rails 4. Pokud není připojen, ověřte pingy serveru a znovu připojte.

2
Matt Connolly

Nejprve určete max_connections v MySQL:

show variables like "max_connections";

Musíte se ujistit, že počet připojení, které provádíte v aplikaci Ruby on Rails, je menší než maximální povolený počet připojení. Všimněte si, že další připojení mohou pocházet z vašich procesů cron jobs, delayed_job (každá by měla stejnou velikost fondu ve vašem database.yml), atd.

Sledujte připojení SQL, když procházíte svou aplikací, spouštíte procesy atd. Následujícím způsobem v MySQL:

show status where variable_name = 'Threads_connected';

Možná budete chtít zvážit uzavření připojení po dokončení zpracování Thread, protože databázová připojení se nezavřou automaticky (myslím, že je to menší problém s aplikacemi Ruby on Rails 4 Reaper ):

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
2
Abdo

Připojení k serveru MySQL je pravděpodobně načasováno.

Měli byste být schopni prodloužit časový limit v MySQL, ale pro správnou opravu nechte svůj kód zkontrolovat, zda je připojení k databázi stále naživu, a pokud to není, znovu se připojte.

1
David Precious

Sledujete počet otevřených připojení nebo podprocesů MySQL? Jaká je vaše nastavení mysql.ini pro max_connections?

mysql> show status;

Podívejte se na Připojení, Max_used_connections, Threads_connected a Threads_created.

Možná budete muset zvýšit limity ve vaší konfiguraci MySQL, nebo možná Rails spojení nezavírá správně *.

Poznámka: Krátce jsem použil Ruby on Rails ...

Dokumentace MySQL pro stav serveru je v http://dev.mysql.com/doc/refman/5.0/en/server-status-variables.html .

1
Z99

Použití funkce reconnect: true v databázi database.yml způsobí, že připojení k databázi bude znovu navázáno po aktivaci chyby ActiveRecord :: StatementInvalid (jak je zmíněno Dave Cheney).

Přidání opakování na operaci databáze se zdálo být nezbytné pro ochranu před uplynutím časového limitu připojení:

begin
  do_some_active_record_operation
rescue ActiveRecord::StatementInvalid => e
  Rails.logger.debug("Got statement invalid #{e.message} ... trying again")
  # Second attempt, now that db connection is re-established
  do_some_active_record_operation
end
1
Graeme Irwin

Měl jsem tento problém v aplikaci Ruby on Rails 3, s použitím drahokamu mysql2. Zkopíroval jsem urážlivý dotaz a pokusil jsem se ho spustit přímo v MySQL a dostal jsem stejnou chybu, "MySQL server odešel.".

Dotazovaný dotaz byl velmi, velmi velký. Velmi velká vložka (+1 MB). Pole, do kterého jsem se pokoušel vložit, bylo ve sloupci TEXT a jejich maximální velikost je 64 KB. Spíše než odhodit chybu, spojení zmizelo.

Zvětšil jsem velikost pole a dostal jsem to samé, takže si stále nejsem jistý, co přesně to bylo. Jde o to, že to bylo v databázi kvůli nějakému podivnému dotazu. Tak jako tak!

0
Ryan Allen

Něco jiného, ​​co zkontrolovat, je Unicorn config. Viz before_fork a after_fork zpracování spojení ActiveRecord zde: https://Gist.github.com/nebiros/2776085#file-Unicorn-rb

0
mahemoff