我们在生产中将Sneakers宝石用于大型应用。有时负载可能非常大,以至于一个特定的队列可能包含250_000条以上的消息。在这种情况下,例外情况
ActiveRecord::ConnectionTimeoutError:
could not obtain a connection from the pool within 5.000 seconds (waited 5.000 seconds); all pooled connections were in use
定期发生。
对于数据库,我们使用的是基于PostgreSQL 9.6的Amazon RDS。 max_connections
PostgreSQL的配置值为3296。
我们的database.yml
文件:
production:
adapter: postgresql
encoding: utf8
pool: 40
database: <%= ENV['RDS_DB_NAME'] %>
username: <%= ENV['RDS_USERNAME'] %>
password: <%= ENV['RDS_PASSWORD'] %>
host: <%= ENV['RDS_HOSTNAME'] %>
port: <%= ENV['RDS_PORT'] %>
我想我们可以增加一个pool
值,但是我找不到有关如何计算最大可能值的信息,因此它不会破坏任何内容。
此外,使用Sneakers gem进行后台处理的应用程序副本也单独存在(但使用相同的数据库),并且可以单独配置。但是现在它具有相同的database.yml
配置。运动鞋gem配置文件:
production:
heartbeat: 2000
timeout_job_after: 35
exchange_type: :fanout
threads: 4
prefetch: 4
durable: true
ack: true
daemonize: true
retry_max_times: 5
retry_timeout: 2000
workers: 4
我们在基本运行时应用程序中的连接池没有问题,但是ActiveRecord::ConnectionTimeoutError
经常出现在工作程序中,这是一个很大的问题。
因此,请帮助我重新配置databese.yml
文件:
pool
选项的最大可能值
如果数据库max_connections
的值为3296?pool
选项的最大可能值
搭配以上配置使用Sneakers gem时?ActiveRecord::ConnectionTimeoutError
?谢谢。
答案 0 :(得分:0)
在等待答案的同时,我一直在寻找解决方案。
而且,我想我最基本的问题是连接池的大小。
在Sneakers gem问题跟踪器上,我找到了一个comment,其中包含用于计算满负载下所需连接数的公式。我从注释中稍微更改了代码,因此现在考虑到每个工作人员的个人设置进行计算:
before_fork = -> {
ActiveSupport.on_load(:active_record) do
ActiveRecord::Base.connection_pool.disconnect!
Sneakers.logger.info('Disconnected from ActiveRecord!')
end
}
after_fork = -> {
def count_pool_size
workers = ::Sneakers::Worker::Classes
default_threads_size = ::Sneakers.const_get(:CONFIG)[:threads]
base_pool_size = 3 + workers.size * 3
if Sneakers.const_get(:CONFIG)[:share_threads]
base_pool_size + default_threads_size
else
base_pool_size + connections_per_worker(workers, default_threads_size)
end
end
def connections_per_worker(classes, default)
classes.inject(0) do |sum, worker_class|
sum + (worker_class.queue_opts[:threads] || default)
end
end
def reconfig?
Rails.env.production?
end
ActiveSupport.on_load(:active_record) do
config = Rails.application.config.database_configuration[Rails.env]
config.merge!('pool' => count_pool_size) if reconfig?
ActiveRecord::Base.establish_connection(config)
Sneakers.logger.info("Connected to ActiveRecord! Config: #{config}")
end
}
摘要:对于所有工人,我在最大负载下必须限制近600个连接。但是我只有40。现在,我将使用上面的代码。希望这会有所帮助。
答案 1 :(得分:0)
来自here。
在
work()
之后,Active Record似乎没有释放连接。 方法已完成。如果使用Active Record将块传递给ActiveRecord::Base.connection_pool.with_connection
,它将释放 连接完美。
def work(msg)
id = JSON.parse(msg)['id']
ActiveRecord::Base.connection_pool.with_connection do
user = User.find(id)
user.name="Homer Simpson"
user.save
end
ack!
end