在查询随机简单查询期间失去与MySQL服务器的连接

时间:2017-07-18 18:04:08

标签: mysql ruby-on-rails ruby activerecord cloud66

最终更新:我们通过找到一种方法来实现我们的目标而不用分叉来解决这个问题。但分叉是问题的原因。

---原帖---

我在rails堆栈上运行ruby,我们的mysql服务器是独立的,但与我们的应用服务器位于同一站点。 (我们尝试将其换成不同规格的mysql服务器,但没有看到任何改进。

在工作时间,我们从没有特定查询中获得了一些这些。

ActiveRecord::StatementInvalid: Mysql2::Error: Lost connection to MySQL server during query

大多数失败的查询都非常简单,并且一个查询与另一个查询之间似乎没有模式。这一切都是从我从Rails 4.1升级到4.2时开始的。

我不知道该尝试什么。我们的数据库服务器全天CPU不到5%。我确实从随机交互失败的用户那里获得了错误报告,所以这不是那些已经运行了几个小时或类似的事情的查询,当然当他们重试它完全相同的事情时。

我们的服务器由cloud66配置。

简而言之:我们的mysql服务器由于某种原因而消失,但这不是因为缺乏资源,而是当我们从这个问题开始时从另一台服务器迁移时它也是一台全新的服务器。

有时在开发功能时我也会在localhost上发生这种情况,所以我不认为这是一个负载问题。

我们正在执行以下操作:

  • ruby​​ 2.2.5
  • rails 4.2.6
  • mysql2 0.4.8

更新:根据下面的第一个答案,我昨晚将max_connections变量增加到500,并确认通过 show global variables like 'max_connections';

我仍然没有断线连接,今天的第一个连接仅在几分钟前被丢弃.... ActiveRecord::StatementInvalid: Mysql2::Error: Lost connection to MySQL server during query

我跑了select * from information_schema.processlist;我又回了36排。这是否意味着我的应用服务器当时正在运行36个连接?或者一个过程可以是多个连接吗?

更新:我刚设置net_read_timeout = 60(之前是30)我会看看是否有帮助

更新:它没有帮助,我仍在寻找解决方案......

在删除凭据后继承我的Database.yml。

production:
  adapter: mysql2
  encoding: utf8
  host: localhost
  database:
  username: 
  password: 
  port: 3306
  reconnect: true

8 个答案:

答案 0 :(得分:3)

与MySQL的连接可以通过多种方式中断,但我建议重新访问Mario Carrion的答案,因为这是一个非常明智的答案。

似乎连接中断,因为它与其他进程共享,导致通信协议错误......

...如果连接池是进程绑定的,这很容易发生,我相信它在ActiveRecord中,这意味着同一个连接可以在不同进程中同时“检出”多次。

解决方案是必须仅在应用程序服务器中的fork语句之后建立数据库连接。

我不确定您使用的服务器,但如果您使用的是warmup功能,请不要这样做。

如果您在第一次网络请求之前运行任何数据库调用 - 请不要。

这些操作中的任何一个都可能在fork发生之前初始化连接池,导致MySQL连接池在进程之间共享,而锁定系统则没有。

我并不是说这是问题的唯一可能原因,正如@ sloth-jr所述,还有其他选择......但根据你的描述,大多数选项似乎不太可能。

旁注:

  

我从information_schema.processlist运行select *;我有36排回来。这是否意味着我的应用服务器当时正在运行36个连接?或者一个过程可以是多个连接吗?

每个进程都可以拥有多个连接。在您的情况下,您最多可能有500X36个连接(参见编辑)

通常,池中的连接数通常与每个进程中的线程数相同(它不应小于线程数,否则争用会降低您的速度)。有时根据您的应用程序添加更多内容是很好的。

修改

我为忽略流程计数引用MySQL数据而不是应用程序数据这一事实而道歉。

您显示的进程计数是MySQL服务器数据,seems to use a thread per connection IO schemeThe "Process" data actually counts active connections而不是实际的进程或线程(尽管它也应该转换为线程数)。

这意味着每个应用程序进程可能有500个连接(即,如果您的应用程序使用8个进程,即8X500 = 4,000个允许的连接),您的应用程序到目前为止只打开了36个连接。

答案 1 :(得分:2)

这表示超时错误。它通常是一般资源或连接错误。

我会在MySQL控制台上检查你的MySQL配置是否有最大连接:

show global variables like 'max_connections';

确保Rails database.yml使用的池连接数小于:

pool: 10

请注意,database.yml反映了单个Rails进程将池化的连接数。如果您有多个进程或其他服务器,如Sidekiq,您需要将它们一起添加。

如果需要在MySQL服务器配置(my.cnf)中增加max_connections,假设你的工具包可以处理它。

[mysqld]
max_connections = 100

注意其他事情也可能会阻塞,例如打开文件,但查看连接是一个很好的起点。

您还可以监控有效查询:

select * from information_schema.processlist;

以及监控MySQL慢速日志。

一个问题可能是长时间运行的更新命令。如果你有一个影响很多记录的慢速运行命令(例如整个表),它甚至可能阻塞最简单的查询。这意味着您可以看到随机查询超时,但如果您检查MySQL状态,真正的原因是另一个长时间运行的查询。

答案 2 :(得分:1)

你没有提到的事情,但你应该看看:

  • 你在使用独角兽吗?如果是,请重新连接并断开after_forkbefore_fork
  • database.yml 配置中是否设置了reconnect: true

答案 3 :(得分:1)

嗯,乍一看,这听起来像你的网络服务器保持mysql会话打开,有时用户会遇到超时。尝试禁用保持mysql会话活动。 这将是一场生猪,但你只使用5%......

其他tipps:

  • 启用mysql"慢查询日志"并看看。

  • 编写一个简短的脚本,每分钟提取并记录mysql进程列表,并用超时交叉检查日志

  • 查看数据库连接中的池大小或设置一个! http://guides.rubyonrails.org/configuring.html#database-pooling 应该等于mysql喜欢的最大连接数!

祝你好运!

答案 4 :(得分:0)

了解您的数据库在多个连接方面是否受到限制。因为通常SQL数据库应该有多个活动连接。 (联系您的网络提供商)

答案 5 :(得分:0)

您介意发布一些查询吗? MySQL文档有这样的说法: https://dev.mysql.com/doc/refman/5.7/en/error-lost-connection.html TL; DR:

  1. 网络问题;你的任何一箱更新租约 定期或遇到其他网络连接错误 (netstat / ss),防火墙超时等。不确定如何管理你的 主机是由cloud66 ....
  2. 查询超时。如果您已备份命令,则可能会发生这种情况     阻止语句(例如,改变/锁定MyISAM上的备份)     表)。你的查询有多简单?没有笛卡尔产品在玩?     EXPLAIN查询可以提供帮助。
  3. 超过MAX_PACKET_SIZE。你在存储图片,视频内容等吗?
  4. 这里有很多可能性,如果没有更多信息,很难确定这一点。

    首先查看mysql_error.log,然后按照自己的方式从数据库服务器返回应用程序。

答案 6 :(得分:0)

更新:这没有用。

下面是解决方案,特别感谢@Myst指出分叉会导致问题,我不知道看看这个特定的代码。因为错误似乎是随机的,因为我们在几个地方以这种方式分叉。

事实证明,当我分叉进程时,rails对所有分叉进程使用相同的数据库连接,这就产生了一种情况,当其中一个进程(父进程?)终止数据库连接时,剩下的进程将连接中断了。

解决方案是更改此代码:

  def recalculate_completion
    Process.fork do
      if self.course
        self.course.user_groups.includes(user:[:events]).each do |ug|
          ug.recalculate_completion
        end
      end
    end
  end

进入此代码:

  def recalculate_completion
    ActiveRecord::Base.remove_connection
    Process.fork do
      ActiveRecord::Base.establish_connection
      if self.course
        self.course.user_groups.includes(user:[:events]).each do |ug|
          ug.recalculate_completion
        end
      end
      ActiveRecord::Base.remove_connection
    end
    ActiveRecord::Base.establish_connection
  end

进行此更改会停止来自我们服务器的错误,现在一切似乎都运行良好。如果有人有任何关于为什么这有效的信息,我会很高兴听到它,因为我希望对此有更深入的了解。

编辑:事实证明这并没有发挥作用......我们仍然断绝了联系,但没有那么多。

答案 7 :(得分:0)

如果您启用了查询缓存,请重置它,它应该可以工作。

重置查询缓存;