【问题标题】:Lost connection to MySQL server during query on random simple queries在对随机简单查询进行查询期间丢失与 MySQL 服务器的连接
【发布时间】:2017-07-18 18:04:07
【问题描述】:

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

---原帖---

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

在工作时间,我们会从没有特定查询的情况下获得其中的一些。

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

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

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

我们的服务器由 cloud66 配置。

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

这也发生在我有时在本地主机上开发功能时,所以我不认为这是一个负载问题。

我们正在执行以下操作:

  • 红宝石 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

【问题讨论】:

  • "一个进程可以是多个连接吗?"一般来说,Rails 进程可以使用 database.yml 池中指定的尽可能多的连接,这是上限,因为它们是按需创建并添加到池中的。
  • 你使用的是哪个版本的mysql2 gem?
  • 正在运行版本 0.4.8
  • 嗨@denodster 这个问题有什么运气吗?没有看到任何更新:)
  • 结论是分叉不是 Rails 可以处理的,所以我从我们的应用程序中删除了所有分叉,最后我采用了一种不需要我们分叉的不同方法。

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


【解决方案1】:

与 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 个连接。

【讨论】:

  • 有没有办法在数据库中查询活动连接列表?而不是活动进程?
  • @denodster 我为写错道歉,尽管数据是 Ruby 应用程序进程计数。MySQL 查询实际上提供了打开的连接数据(36 个连接)。
  • 无论哪种方式,我相信这让我走上了正确的道路,我在几个地方分叉以产生子进程,我发现它会干扰数据库连接,所以我重写了这些部分我们的应用程序,今晚我将使用该修复程序上线,我们将看看它是否有效。
  • 到目前为止一切顺利,我今天还没有看到任何数据库连接失败,我会再给它几天,并写下我究竟做了什么来修复。
  • @denodster 我很高兴能通过指出有关fork 和数据库连接的问题来提供帮助。
【解决方案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 状态,真正的原因是另一个长时间运行的查询。

【讨论】:

  • 我的 database.yml 没有最大连接数的配置行。你知道在这种情况下是否有办法找出默认值是什么?
  • 你可以在mysql控制台上运行show global variables like 'max_connections';。
  • 感谢您的回复,我已经尝试了您的建议,但我仍然失去了联系,我已经更新了我的问题,并详细说明了我所做的事情。
【解决方案3】:

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

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

【讨论】:

  • 我不相信我在使用独角兽,因为我不知道独角兽是什么。 reconnect: true 在我的 database.yml 中设置。
  • @denodster unicorn 是一个 Web 应用程序服务器。如果您不确定您使用的是哪个服务器,您可能正在使用puma。但是,puma 也是一个多进程服务器,因此您可能会遇到类似的问题。
  • 我正在使用 nginix,并且在我的本地很瘦
【解决方案4】:

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

其他提示:

祝你好运!

【讨论】:

    【解决方案5】:

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

    重置查询缓存;

    【讨论】:

      【解决方案6】:

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

      【讨论】:

      • 我如何找到这个?
      【解决方案7】:

      您介意发布一些查询吗? 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。您是在存储图片、视频内容等吗?

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

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

      【讨论】:

        【解决方案8】:

        更新:这不起作用。

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

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

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

        【讨论】:

          猜你喜欢
          • 2015-11-22
          • 1970-01-01
          • 2015-09-22
          • 1970-01-01
          • 2012-11-15
          • 2020-07-11
          • 2020-12-05
          • 1970-01-01
          • 2015-06-27
          相关资源
          最近更新 更多