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

Lost connection to MySQL server during query on random simple queries

最终更新:我们通过找到一种无需分叉即可实现目标的方法来解决此问题。但是分叉是问题的原因。

---原版Post---

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

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

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

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

我不知道该尝试什么。我们的数据库服务器全天不到 5% CPU。我确实收到了 运行dom 交互因此失败的用户的错误报告,所以这不是 运行 几个小时或类似的查询,当然,当他们重试完全相同的事情时有效。

我们的服务器是由cloud66配置的。

所以简而言之:我们的 mysql 服务器由于某种原因要离开了,但这不是因为缺乏资源,它也是一个 b运行d 新服务器,因为我们从另一个服务器迁移时这个问题开始了。

有时在开发功能时,我在本地主机上也会遇到这种情况,所以我认为这不是负载问题。

我们运行以下:

更新:根据下面的第一个答案,我昨晚将 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

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

我会在 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 慢速日志。

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

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

您介意发布您的一些查询吗? MySQL 文档对此有如下说明: https://dev.mysql.com/doc/refman/5.7/en/error-lost-connection.html 长话短说:

  1. 网络问题;你们有没有续租的盒子 定期,或遇到其他网络连接错误 (netstat / ss)、防火墙超时等。不确定您的管理方式 主机由 cloud66 提供....
  2. 查询超时。如果您备份了命令,就会发生这种情况 在阻塞语句之后(例如,MyISAM 上的 alters/locking 备份 表)。您的查询有多简单?没有笛卡尔积在起作用? EXPLAIN 查询可能有所帮助。
  3. 超过MAX_PACKET_SIZE。您是否存储图片、视频内容等?

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

首先查看 mysql_error.log,然后从数据库服务器返回到您的应用程序。

你没有提到但你应该看看的东西:

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

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

其他小费:

祝你好运!

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

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

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

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

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

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

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

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

旁注:

I ran select * from information_schema.processlist; and I got 36 rows back. Does this mean my app servers were running 36 connections at that moment? or can a process be multiple connections?

每个进程可以持有多个连接。在您的情况下,您可能有多达 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 个连接。

更新:这没有用。

这是解决方案,特别感谢@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

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

编辑:事实证明这也不起作用....我们仍然遇到连接断开但不那么频繁的情况。

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

重置查询缓存;