Rails Puma用完了Redis连接

时间:2015-08-04 13:15:52

标签: ruby-on-rails heroku redis connection-pooling puma

我已经在SO上查看了其他类似的问题但是不能很好地将事情拼凑在一起。我有一个Rails应用程序(在Heroku上),它使用Puma同时具有多个进程和多个线程。我的应用程序还使用Redis作为辅助数据存储(除SQL数据库之外),直接查询Redis(通过connection_pool gem)。这是我的Puma配置文件:

workers Integer(ENV["WEB_CONCURRENCY"] || 4)
threads_count = Integer(ENV["MAX_THREADS"] || 5)
threads threads_count, threads_count

preload_app!

rackup DefaultRackup
port ENV["PORT"] || 3000
environment ENV["RACK_ENV"] || "development"

on_worker_boot do
  # Worker specific setup for Rails 4.1+
  ActiveRecord::Base.establish_connection

  redis_connections_per_process = Integer(ENV["REDIS_CONNS_PER_PROCESS"] || 5)
  $redis = ConnectionPool.new(size: redis_connections_per_process) do
    Redis.new(url: ENV["REDIS_URL"] || "redis://localhost:6379/0")
  end
end

My Redis实例的连接限制为20,我发现自己经常超过这个限制,尽管应该是(据我所知)每个进程只有5个连接分布在4个工作进程中。

事实上,当我将max number of clients reached设置为1时,我甚至会收到REDIS_CONNS_PER_PROCESS Redis错误。是否为每个线程而不是每个进程调用on_worker_boot

我还尝试过使用单独的redis.rb初始值设定项,即使REDIS_CONNS_PER_PROCESS为1,它仍然会给我带来错误。这看起来很奇怪,因为我应该可以将它设置为4正确地做我的数学(4个工作进程+ 1个主进程)*每个进程4个连接。 (请注意,出于这个问题的目的,我忽略了部署时出现的错误,因为我假设Heroku可能在该过程中连接新旧进程,即使我没有使用Preboot。)

我在哪里误解了这一切是如何融合在一起的?

3 个答案:

答案 0 :(得分:2)

我有类似的问题。起初我使用redis-togo,它没有问题。但是当我从redis-togo改为Heroku redis之后,我得到了“ERR最大客户数达到”错误。

我的应用程序代码没有更改,redis提供商的更改是唯一的。

我在Heroku支持下打开了一张票,他们建议我更改超时值的默认设置。

https://devcenter.heroku.com/articles/heroku-redis#configuring-your-instance

在我更改了Heroku redis的默认超时值后,每个人都解决了。 我想redis提供程序的redis timeout的默认值是不同的。和Heroku redis的默认设置为0。 “值为零意味着连接不会被关闭。”

我希望我的经验很有帮助。

答案 1 :(得分:1)

在进一步阅读和测试之后,我最终将我的Redis连接池代码移动到一个单独的初始化程序中。不幸的是,这根本没有解决我的问题 - 尽管对流程和连接数进行了大量修改,但在我应该出现之前,我仍然遇到max number of clients reached错误。

事实证明,答案是将Redis提供商从Heroku Redis切换到Redis Cloud。我不确定为什么Heroku Redis不允许它所宣传的连接数量,但在一些调查中,Redis Cloud实际上似乎允许更多连接而不是广告(或者至少限制连接透明且无错误)没有任何问题。哇。他们肯定赢得了我的业务。

答案 2 :(得分:1)

我也遇到了这个问题,虽然Heroku Redis仪表板只显示了几个连接,但我的连接已经用完了。

然后我联系了Heroku支持,他们告诉我仪表板只显示活动的客户端/连接,而不是空闲的。

因此Redis超时为0(永不超时),重启后Redis连接空闲,新的连接打开。因此,每次重启都会导致情况恶化

如本页其他人所述,解决方案是将超时设置为0以外的其他值:

heroku redis:timeout -s 10 -a APPLICATION_NAME

这会使连接在10秒后死亡,这应该不是问题,因为在使用它时它将保持打开状态(没有不必要的关闭)。

当您的流量很少时,您可能会考虑将其设置为更高的值。