6

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

---原帖---

我在 Rails 堆栈上运行 ruby​​,我们的 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
4

8 回答 8

6

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

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

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

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

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

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

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

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

边注:

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

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

一般来说,池中的连接数通常可以与每个进程中的线程数相同(它不应小于线程数,否则争用会减慢您的速度)。有时根据您的应用程序添加更多是很好的。

编辑:

对于忽略进程计数引用 MySQL 数据而不是应用程序数据这一事实,我深表歉意。

您显示的进程计数是 MySQL 服务器数据,似乎每个连接 IO 方案使用一个线程“进程”数据实际上计算活动连接而不是实际进程或线程(尽管它也应该转换为线程数)。

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

于 2017-08-08T14:25:08.620 回答
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 状态,真正的原因是另一个长时间运行的查询。

于 2017-07-18T21:58:14.003 回答
1

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

  • 你在用独角兽吗?如果是这样,您的和中是否重新连接和断开after_fork连接before_fork
  • reconnect: true在你的database.yml配置中设置的吗?
于 2017-08-04T18:13:15.533 回答
1

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

重置查询缓存;

于 2019-05-01T03:44:45.853 回答
1

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

其他提示:

  • 开启mysql“慢查询日志”看看。

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

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

祝你好运!

于 2017-08-07T17:24:56.207 回答
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

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

编辑:事实证明这也不起作用....我们仍然有掉线但不那么频繁。

于 2017-08-31T15:14:41.313 回答
0

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

于 2017-08-02T20:00:11.980 回答
0

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

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

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

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

于 2017-08-03T19:03:58.623 回答