Ошибка Rails 3.1 / mysql2: «сервер MySQL ушел» - PullRequest
7 голосов
/ 23 декабря 2011

У меня возникают проблемы при обновлении приложения rails 2.3.14 / ruby ​​1.8.7 до версии 3.1.1 / 1.9.2: у меня возникают некоторые

(ActiveRecord::StatementInvalid) "Mysql2::Error: MySQL server has gone away"

ошибки, возникающие время от времени.Важно уточнить, что у меня никогда не было таких проблем с гемом mysql в 2.3.14 и точно такой же БД (поэтому ошибка не должна исходить из mysql (v5.5.10)).

Пример:

$ rails c production
Loading production environment (Rails 3.1.1)
ruby-1.9.2-p290 :001 > ActiveRecord::Base.connection.active?
 => false
ruby-1.9.2-p290 :002 > exit
$ rails c production
Loading production environment (Rails 3.1.1)
ruby-1.9.2-p290 :001 > ActiveRecord::Base.connection.active?
 => true 

Это происходит только с моей (удаленной) производственной базой данных, никаких проблем с моей локальной базой данных разработки.Я пытался установить «connect: true »в моем database.yml, но это привело к

Mysql2::Error: Host '****' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts':...

Я пытался изолировать проблему с помощью небольшого сценария rb, загружающего только mysql2 и activerecord, ноне удалось воспроизвести ошибку таким образом (поэтому она может быть связана со стеком рельсов).

Я не могу вернуться от «mysql2» к «mysql» из-за проблем с кодировкой (http://www.rorra.com.ar/2010/07/30/rails-3-mysql-and-utf-8/).Как следствие, мне пришлось откатить свою продукцию до моего приложения rails 2.3.14, которое меня очень огорчает ...

Вы видите, что я могу сделать, чтобы отладить это?Я даже не могу найти верный способ воспроизвести ошибку ... Кто-нибудь встречал такую ​​же ошибку?

Я только нашел несколько людей, упоминающих эту ошибку (например: https://github.com/brianmario/mysql2/issues/213), но не решение.

Спасибо за вашу помощь.

Ответы [ 2 ]

12 голосов
/ 23 декабря 2011

Хорошо, думаю, я решил свою проблему. Я не заметил этого, когда отправил свой вопрос, но казалось, что ошибка связана с тайм-аутом: примерно через 20 секунд activerecord теряет соединение.

$ rails runner "sleep 23; puts ActiveRecord::Base.connection.active?"
=> true
$ rails runner "sleep 25; puts ActiveRecord::Base.connection.active?"
=> false

Итак, я продолжил копать и понял, что гемы mysql и mysql2 не работают с параметром MySQL 'wait_timeout' так же, как и в случае с mysql, гем не устанавливает его, поэтому использует значение по умолчанию MySQL 28800 тогда как mysql2 gem устанавливает его в 2592000 , если он не определен в database.yml. Но у меня сложилось впечатление, что значение 2592000 превышает максимальное значение для этого параметра: 2147483 ! Что может привести к неожиданному поведению, которое я описал ...

Я создаю тестовый скрипт, показывающий ошибку: https://gist.github.com/1514154

И если при загрузке консоли rails у меня был какой-то случайный разрыв соединения (см. Мой вопрос), я думаю, это из-за того, что моему приложению потребовалось много времени для загрузки, и я иногда ждал несколько секунд, прежде чем набрать свою команду.

Я не могу объяснить, почему мы так мало сталкиваемся с этой проблемой. Возможно, это относится к моему conf (удаленная база данных, версия MySQL?). Я пытался с другой удаленной базой данных: ошибка не воспроизводится ...

Итак, в заключение я установлю wait_timeout: 2147483 в моем database.yml. А может быть, потяните запрос рельсы ...

2 голосов
/ 23 декабря 2011

У меня было много потерянных соединений - но я не мог сказать, разорвались ли они из-за следующего изменения или в противном случае: /

Пришлось добавить следующий скрипт в инициализаторы и добавить строку конфигурации для каждой из моих баз данных в моем database.yml следующим образом:

...
flags: <%= 65536 | 131072 %>
...

Сценарий выглядит так:

/ конфигурации / Инициализаторы / mysql2.rb

module ActiveRecord
  class Base
    # Overriding ActiveRecord::Base.mysql2_connection
    # method to allow passing options from database.yml
    #
    # Example of database.yml
    #
    #   login: &login
    #     socket: /tmp/mysql.sock
    #     adapter: mysql2
    #     host: localhost
    #     encoding: utf8
    #     flags: 131072
    #
    # @param [Hash] config hash that you define in your
    #   database.yml
    # @return [Mysql2Adapter] new MySQL adapter object
    #
    def self.mysql2_connection(config)
      config[:username] = 'root' if config[:username].nil?

      if Mysql2::Client.const_defined? :FOUND_ROWS
        config[:flags] = config[:flags] ? config[:flags] | Mysql2::Client::FOUND_ROWS : Mysql2::Client::FOUND_ROWS
      end

      client = Mysql2::Client.new(config.symbolize_keys)
      options = [config[:host], config[:username], config[:password], config[:database], config[:port], config[:socket], 0]
      ConnectionAdapters::Mysql2Adapter.new(client, logger, options, config)
    end
  end
end
...