我有一个 Rails 系统,其中每半小时执行一次以下操作:
- 网络上其他地方有 15 个客户端
- 服务器为每个客户端创建一个名为
Measurement
的记录 - 配置测量记录,然后使用
MeasurementWorker.perform_async(m.id)
通过 Sidekiq 异步运行它们
- 与客户端的连接是通过 Celluloid actors 和 WebSocket 客户端完成的
- 每个测量在运行时都会创建一些存储在数据库中的事件记录
系统一直在5个客户端运行良好,但是现在我15个,同时启动时很多测量都跑不起来了,报如下错误:
2015-02-04T07:30:10.410Z 35519 TID-owd4683iw MeasurementWorker JID-15f6b396ae9e3e3cb2ee3f66 INFO: fail: 5.001 sec
2015-02-04T07:30:10.412Z 35519 TID-owd4683iw WARN: {"retry"=>false, "queue"=>"default", "backtrace"=>true, "class"=>"MeasurementWorker", "ar
gs"=>[6504], "jid"=>"15f6b396ae9e3e3cb2ee3f66", "enqueued_at"=>1423035005.4078047}
2015-02-04T07:30:10.412Z 35519 TID-owd4683iw WARN: could not obtain a database connection within 5.000 seconds (waited 5.000 seconds)
2015-02-04T07:30:10.412Z 35519 TID-owd4683iw WARN: /home/webtv/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/activerecord-4.1.4/lib/active_
record/connection_adapters/abstract/connection_pool.rb:190:in `block in wait_poll'
....
现在,我的生产环境是这样的:
config/sidekiq.yml
production:
:verbose: false
:logfile: ./log/sidekiq.log
:poll_interval: 5
:concurrency: 50
config/unicorn.rb
...
worker_processes Integer(ENV["WEB_CONCURRENCY"] || 3)
timeout 60
...
config/database.yml
production:
adapter: postgresql
database: ***
username: ***
password: ***
host: 127.0.0.1
pool: 50
postgresql.conf
max_connections = 100 # default
如您所见,我已经将 Sidekiq 的并发性增加到 50,以满足大量可能的并发测量。我已将数据库池设置为 50,这对我来说已经有点大材小用了。
我应该补充一点,服务器本身非常强大,配备 8 GB RAM 和四核 Xeon E5-2403 1.8 GHz。
理想情况下,这些值应该设置为多少?我可以使用什么公式来计算它们? (例如最大数据库连接数 = Unicorn worker × Sidekiq 并发数 × N)
最佳答案
在我看来,您的池配置 100 没有生效。每个进程最多需要 50 个,因此将 100 更改为 50。我不知道您是否使用 Heroku,但众所周知,配置池大小非常困难。
在 mysql 内部,您的最大连接数应该如下所示:
((Unicorn processes) * 1) + ((sidekiq processes) * 50)
Unicorn 是单线程的,永远不需要多个连接,除非您出于某种原因在 Rails 应用中启动自己的线程。
关于ruby-on-rails - 如何防止数据库连接在 Rails 中超时?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28316298/