Rails 3.1 / mysql2错误:"MySQL服务器已关闭"

8
我正在升级我的rails 2.3.14 / ruby 1.8.7应用到3.1.1/1.9.2,但遇到了麻烦:我有一些

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

错误出现得很零散。重要的是要明确,在2.3.14版本和完全相同的数据库上,我从未遇到过“mysql”宝石的这种问题(因此错误不应该来自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 

这仅在我的(远程)生产数据库中发生,我的本地开发 db 没有问题。我尝试在我的 database.yml 中设置 "reconnect: true",但导致了一个问题。
Mysql2::Error: Host '****' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts':...

我尝试使用一个小的rb脚本仅加载mysql2和activerecord来隔离问题,但我没有成功复现这个bug(因此可能与rails堆栈有关)。

由于编码问题,我无法从'mysql2'退回到'mysql' gem(http://www.rorra.com.ar/2010/07/30/rails-3-mysql-and-utf-8/),因此,我不得不将我的生产环境回滚到我的rails 2.3.14应用程序,这让我非常沮丧...

你看我能做些什么来调试这个问题吗?我甚至找不到一个确定的方法来复现这个错误...有人遇到过同样的bug吗?

我只发现很少有人提到这个bug(例如:https://github.com/brianmario/mysql2/issues/213),但没有解决方案。

谢谢你的帮助。

2个回答

13

好的,我想我解决了我的问题。当我发布问题时没有注意到,但似乎错误与超时有关:大约20秒后,活动记录失去了连接。

$ rails runner "sleep 23; puts ActiveRecord::Base.connection.active?"
=> true
$ rails runner "sleep 25; puts ActiveRecord::Base.connection.active?"
=> false
所以我继续深入研究后发现mysql和mysql2的宝石(gem)没有以相同的方式处理MySQL的'wait_timeout'参数:mysql宝石不设置它,因此使用MySQL默认值28800,而mysql2宝石在database.yml中如果未定义则将其设置为2592000
但是我有这样的印象,即值2592000超过了此参数的最大值:2147483!这可能导致我所描述的意外行为...
我编写了一个脚本测试来展示这个错误:https://gist.github.com/1514154 如果我在加载rails控制台时遇到某些看似随机的断开连接(参见我的问题),我认为这是因为我的应用需要很长时间才能加载,有时我需要等待几秒钟才能输入命令。
我无法解释为什么我们遇到这个问题的人如此之少。也许这是特定于我的配置(远程数据库,MySQL版本之类的)。我已经尝试使用另一个远程staging数据库:错误没有重现...
因此,作为结论,我将在我的database.yml中设置wait_timeout:2147483。也许可以向rails发起拉取请求...

2147483限制是针对Windows的,对吧?它在“类型(Windows)”块中。对于其他平台,限制为31536000。http://dev.mysql.com/doc/refman/5.5/en/server-system-variables.html#sysvar_wait_timeout - kenn
在Windows 7中使用mysql2 0.3.16activerecord 4.0.0/4.1.4进行测试,wait_timeout是有效的,但在实际的Rails应用中,我遇到了失去连接甚至内存不足的问题。 - Paul

2

我遇到了很多断开的连接——但我无法确定它们是因为以下调整还是其他原因消失了 :/

必须将以下脚本放入initializers中,并在我的database.yml的每个数据库中添加一行配置,就像这样:

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

这是脚本的样子:
/config/initializers/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

1
谢谢你的回答,但我不认为我们的两个问题有关系:你的应用程序可能有多语句/多结果查询吗?因为你添加的标志对应于CLIENT_MULTI_RESULTS和CLIENT_MULTI_STATEMENTS,是吗?顺便说一下,使用Mysql2 :: Client :: MULTI_STATEMENTS和Mysql2 :: Client :: PS_MULTI_RESULTS(而不是原始整数)应该可以解决问题。 - Flackou

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接