如何防止数据库连接在 Rails 中超时?

How can I prevent database connections from timing out in Rails?

我有一个 Rails 系统,其中每半小时执行一次以下操作:

系统在 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。

理想情况下,这些值应该设置为多少?我可以使用什么公式来计算它们? (例如最大DB连接数=Unicorn workers×Sidekiq并发数×N

在我看来,您的池配置 100 没有生效。每个进程最多需要 50 个,因此将 100 更改为 50。我不知道您是否使用 Heroku,但众所周知,配置池大小非常困难。

在 mysql 中,您的最大连接数应如下所示:

((Unicorn processes) * 1) + ((sidekiq processes) * 50)

Unicorn 是单线程的,永远不需要多个连接,除非您出于某种原因在 Rails 应用程序中启动自己的线程。

我确信 sidekiq 的创建者 @MikePerham 非常适合解决您的 sidekiq 问题,但作为 ruby 开发者,有两件事很突出。

如果您通过 ruby 执行大量数据库操作,您可以将其中一些作为 triggers 推送到数据库中吗?当然,您仍然可以使用 sidekiq 进程在应用端启动它们。 :)

每半小时第二次通过 cron 向我尖叫 运行 rake 任务。希望你也在这样做。 FWIW 我通常使用 Whenever gem to create the cron line I have to drop into the crontab of the user running the app. Note its designed to autocreate the crontask in a scripted deploy but in a non-scripted one you can still leverage it to give you the lines you have to paste into your crontab though via the whenever 命令。

你还提到这是为了测量。

你有没有考虑过利用 elasticsearch and the searchkick gem? This is a little more of a complex setup, be sure to firewall the server you install ES on. But this might make your code a lot more manageable as you grow. Also it gives you a good search mechanism almost for free and its distributed and more language agnostic, e.g. Bloodhound, Java. :) Plus kibana 这样的东西给你一个很好的 window 进入 ES 记录