我每天要获得ActiveRecord::ConnectionTimeoutError
一次或两次。有人可以帮助我计算应用程序与数据库的连接数吗?和建议来优化我的联系?
这是我的配置
AWS
Database : Mysql
Version : 5.7.23
Provider : AWS RDS (db.m5.large, vCPU: 2, RAM: 8GB)
具有波纹管配置的3台服务器
# database.yml
pool: 20
# puma.rb
RAILS_MAX_THREADS : 5
WEB_CONCURRENCY : 2
1个具有波纹管配置的sidekiq服务器
# sidekiq
concurrency: 25
我试图获得数据库能够处理的最大连接数
# MySQL Max connections ("show global variables like 'max_connections';")
624
与数据库的连接总数等于每台服务器的连接数乘以服务器数。
总数据库连接数=每个服务器的连接数*服务器数。
[每台服务器的连接数= AR数据库池大小*每台服务器的进程(通常使用WEB_CONCURRENCY或SIDEKIQ_COUNT设置)
因此对于Web服务器,您具有:
AR数据库池大小= 20
每个服务器的进程= 2
服务器数量= 3
总数据库连接(Web服务器)= 20 * 2 * 3 = 120
sidekiq服务器的:
AR数据库池大小= 20
每个服务器的进程= 1
服务器数量= 1
总数据库连接(Sidekiq服务器)= 20 * 1 * 1 = 20
因此,预期的数据库连接总数应为140
,这远低于RDS实例的限制。
我的猜测是,您得到ActiveRecord::ConnectionTimeoutError
的原因是您的Sidekiq并发设置高于AR连接池的值。所有的Sidekiq线程都需要一个ActiveRecord数据库连接,因此将AR池大小设置为比Sidekiq的并发数小的数字意味着某些Sidekiq线程将被阻塞,以等待空闲的数据库连接。在您的情况下,在某个时间点,您可能有25个线程试图通过最多可使用20个连接的数据库池访问数据库,并且如果某个线程在5秒钟内无法获得免费的数据库连接,您将获得一个连接超时错误。
在Sidekiq中,总的数据库连接应为
最小(需要数据库连接的线程,AR数据库池大小)*每个服务器的进程数(WEB_CONCURRENCY或SIDEKIQ_COUNT)*服务器数。
另外,Sidekiq documentation指出
[从Rails 5开始,RAILS_MAX_THREADS可用于配置Rails和Sidekiq并发。请注意,ActiveRecord具有一个连接池,需要在config / database.yml中对其进行正确配置,以便在大量并发情况下正常工作。将池设置为等于线程数
pool: <%= ENV['RAILS_MAX_THREADS'] || 10 %>
此答案大部分基于[Nate Berkopec中的Sidekiq in Practice电子邮件系列”>