Rails Puma 运行 Redis 连接不足

Rails Puma running out of Redis connections

我已经查看过关于 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

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

事实上,当我将 REDIS_CONNS_PER_PROCESS 设置为 1 时,我什至会遇到 max number of clients reached Redis 错误。on_worker_boot 是针对每个线程而不是每个进程调用的吗?

我也尝试过使用单独的 redis.rb 初始化器,即使 REDIS_CONNS_PER_PROCESS 为 1,它仍然会给我错误。这看起来很奇怪,因为如果我的数学运算正确(4 个工作进程 + 1 个主进程)* 每个进程 4 个连接。 (请注意,出于这个问题的目的,我忽略了部署过程中发生的错误,因为我假设 Heroku 可能会在该过程中连接新旧进程,即使我没有使用 Preboot。)

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

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

事实证明,答案是将 Redis 提供商从 Heroku Redis 切换到 Redis Cloud。我不确定为什么 Heroku Redis 不允许它宣传的连接数,但经过一些调查,Redis Cloud 实际上似乎允许比宣传的 更多 连接(或至少透明地限制连接并且没有错误)没有任何问题。哇。他们肯定赢得了我的生意。

我有类似的问题。一开始我用的是redis-togo,没问题。但是在我从 redis-togo 更改为 Heroku redis 之后,我得到了 "ERR max number of clients reached" 个错误。

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

我在 Heroku 支持处开了一个工单,他们建议我更改超时值的默认设置。

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

我更改了Heroku redis的默认超时值后,一切都解决了。 我猜 redis 提供者的 redis 超时默认值是不同的。而 Heroku redis 的默认设置是 0。 "A value of zero means that connections will not be closed."

希望我的经验对您有所帮助。

我也 运行 遇到了这个问题,虽然 Heroku Redis 仪表板只显示了几个连接,但我 运行 没有连接。

然后我联系了 Heroku 支持,他们告诉我仪表板 只显示活动的 clients/connections,而不显示空闲的。

因此,由于 Redis 超时为 0(从不超时),因此在重新启动时,Redis 连接空闲并打开新连接。所以情况 每次重启都会变得更糟

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

heroku redis:timeout -s 10 -a APPLICATION_NAME

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

当您的流量很少时,您可以考虑将此值设置得更高一些。