在查询随机简单查询时丢失与MySQL服务器的连接

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

---原帖---

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

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

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

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

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

我们的服务器由cloud66配置。

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

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

我们运行以下内容:

红宝石2.2.5 铁轨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
3
投票

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

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

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

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

我不确定你使用的服务器,但如果你使用的是warmup功能 - 请不要。

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

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

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

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

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

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

编辑:

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

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

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

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状态,真正的原因是另一个长时间运行的查询。

1
投票

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

你在使用独角兽吗?如果是这样,你的 after_forkbefore_fork重新连接和断开连接? reconnect: true是否在database.yml配置中设置?
1
投票

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

其他提示:

启用mysql“慢查询日志”并查看。 写一个简短的脚本,每分钟拉出并记录mysql进程列表,并用超时交叉检查日志 查看数据库连接中的池大小或设置一个! http://guides.rubyonrails.org/configuring.html#database-pooling应该等于mysql喜欢的max-connections!

祝好运!

0
投票

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

0
投票

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

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

这里有很多可能性,如果没有更多信息,将难以确定这一点。

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

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

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

编辑:事实证明这不起作用....我们仍然有连接断开但没有那么多。

0
投票

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

重置QUERY CACHE;