【问题标题】:ActiveRecord::ConnectionTimeoutError: could not obtain a database connection within 5.000 secondsActiveRecord::ConnectionTimeoutError: 无法在 5.000 秒内获得数据库连接
【发布时间】:2021-05-13 06:27:17
【问题描述】:

我在我的 Prod 服务器上偶尔收到此错误。 ActiveRecord::ConnectionTimeoutError: could not obtain a database connection within 5.000 seconds

我看到 DB 的 CPU 使用率不高,但这个错误仍然每天发生一次,也许两次。

Puma.rb

threads 2, 100
workers 2

数据库.yml

  pool: 15

红宝石 红宝石:2.3

彪马

puma (3.11.2)

数据库大小

db.m5.large

【问题讨论】:

  • 你有sidekiq之类的吗?因为它可能需要很多连接
  • 是的,我在同一个实例中的 APP 容器之外的另一个容器中运行了 sidekiq。
  • 这可能是您问题的很大一部分,我建议您阅读并计算您的 Sidekiq 使用了多少个连接stackoverflow.com/questions/58426501/…

标签: ruby-on-rails ruby puma


【解决方案1】:

在您当前的配置中,每个 puma worker 都有自己的连接池,其中包含 15 个可用的数据库连接。每个工作线程可以根据服务器负载在 2 到 100 个线程之间扩展。

这意味着当负载增加或有更多长时间运行的请求时,您的服务器将运行创建超过 15 个线程,此时,您的数据库连接池将为空,新线程必须等待其他线程返回数据库连接。这可能需要一段时间,等待 5 秒后,您将观察到 ActiveRecord::ConnectionTimeoutError 异常。

要解决此问题,您必须确保数据库连接池对于所有线程都足够大。但同时,您必须确保所有池中的所有连接总数 - 在工作人员以及 sidekiq 和其他工具(数据库管理工具或 Rails 控制台)中 - 低于您可用的最大连接数数据库。

我的建议是:首先,确定数据库中的最大连接数。您可能会在数据库的配置或数据库提供商的文档中找到此信息。然后将这个数量的整体工人和像 Sidekiq 这样的工具分开。一旦您知道每个工作人员的最大连接数,请将最大线程数设置为该数字。

示例:您的数据库映像支持 64 个连接。然后,您可能希望运行两台服务器,每台服务器有 2 个工作人员,一个 Sidekiq 实例有 4 个工作人员,并且您希望有一个缓冲区以便能够将 Rails 控制台或备份系统也连接到数据库。

2 servers with 2 workers  48
8 sidekiq workers          8
buffer                     8

有了这些数字,我会将 Rails 数据库配置中的连接池设置为 12,并将 puma 配置中的线程数设置为 2, 12

在 Heroku 开发中心的 Concurrency and Database Connections in Ruby with ActiveRecord 上阅读有关此主题的更多信息。

【讨论】:

  • 是的,我也认为线程数到 100 有点太多了。
  • 对于 db.m5.large,8 GiB:2 个 vCPU,它应该在 676 左右。ref 我的统计数据 3 个服务器,2 个工作人员 * 100 个线程(最大)600 3 个服务器,20 个 sidekiq 工作人员 60 600+60 == 660 我猜它快被消耗掉了。
猜你喜欢
  • 2015-03-04
  • 1970-01-01
  • 2016-04-16
  • 2020-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-07
  • 1970-01-01
相关资源
最近更新 更多