Heroku上的Puma Cluster配置
我在RoR4 Heroku应用程序上配置Puma(multithreading+多核服务器)需要一些帮助。 Heroku上的文档并不是最新的。 我遵循了这个:配置的并发和数据库连接 ,没有提到集群的配置,所以我不得不同时使用这两种类型(线程和多核)。
我目前的配置:
./Procfile
web: bundle exec puma -p $PORT -C config/puma.rb
./config/puma.rb
environment production threads 0,16 workers 4 preload_app! on_worker_boot do ActiveRecord::Base.connection_pool.disconnect! ActiveSupport.on_load(:active_record) do config = Rails.application.config.database_configuration[Rails.env] config['reaping_frequency'] = ENV['DB_REAP_FREQ'] || 10 # seconds config['pool'] = ENV['DB_POOL'] || 5 ActiveRecord::Base.establish_connection end end
问题:
a)我是否需要像Unicorn一样的before_fork / after_fork配置,因为群集工作者是分叉的?
b)如何根据我的应用程序调整我的线程数 – 将它放下的原因是什么? /在什么情况下它会有所作为? 是不是已经优化了0:16?
c)Heroku数据库允许500个连接。 根据线程,工作线程和动态计数,DB_POOL的值是多少? – 并行工作时,每个dyno的每个工作线程的每个线程是否都需要唯一的DB连接?
一般来说:我的配置应该如何兼顾并发性和性能?
a)我是否需要像Unicorn一样的before_fork / after_fork配置,因为群集工作者是分叉的?
通常没有,但是因为你正在使用preload_app
,是的。 预加载应用程序会启动并运行实例,然后为工作人员分配内存空间; 结果是你的初始化程序只运行一次(可能分配数据库连接等)。 在这种情况下,您的on_worker_boot
代码是合适的。 如果您没有使用preload_app
,那么每个工作人员都会自行启动,在这种情况下,使用初始化程序非常适合像您一样设置自定义连接。 实际上,如果没有preload_app
,你的on_worker_boot
块就会出错,因为那时ActiveRecord和朋友甚至都没有加载。
b)如何根据我的应用程序调整我的线程数 – 将它放下的原因是什么? /在什么情况下它会有所作为? 是不是已经优化了0:16?
在Heroku(和我的测试)上,你最好匹配你的min
/ max
线程, max
<= DB_POOL
设置。 min
线程允许您的应用程序在不负载时降低资源,这通常很好地释放服务器上的资源,但在Heroku上可能不太需要; dyno已经致力于提供Web请求,也可以让它们准备就绪。 设置max
线程<=你的DB_POOL
环境变量不是必需的,你冒着在池中消耗所有数据库连接的风险,然后你有一个线程想要连接但是无法获得它,你可以获得旧的“ActiveRecord :: ConnectionTimeoutError – 无法在5秒内获得数据库连接。” 错误。 这取决于你的应用程序,你很可能有max
> DB_POOL
并且没问题。 我会说你的DB_POOL
应该至少与你的min
threads值相同,即使你的连接没有被急切加载(如果你的应用程序永远不会访问数据库,5:5线程也不会打开5个连接)。
c)Heroku数据库允许500个连接。 根据线程,工作线程和动态计数,DB_POOL的值是多少? – 并行工作时,每个dyno的每个工作线程的每个线程是否都需要唯一的DB连接?
生产层允许500,要清楚:)
每个dyno每个工作线程的每个线程都可以使用一个连接,具体取决于它们是否都在同时尝试访问数据库。 通常连接会在完成后重复使用,但正如我在b)
提到的,如果你的线程大于你的池,那么你可能会遇到不好的时间。 连接将被重用,所有这些都由ActiveRecord处理,但有时不理想。 有时连接会闲置或死亡,这就是建议启用Reaper以检测和回收死连接的原因。
您不需要比线程更少的数据库连接。 请记住,每个单独的进程都有自己的连接池,因此如果您的数据库支持20个连接,并且您希望运行2个进程,则可以运行而不会有超时风险的大多数线程是10个线程,每个线程具有10个连接池。
您想为rails控制台会话留下一些连接。 还要注意后台工作者,以及他们是否有线程。
如果您的员工处于单独的流程(sidekiq),他们将拥有自己的池。 如果您的工作线程是从Web进程(girl_friday或sucker_punch)生成的,那么您将希望DB_POOL大于最大Web线程数,因为它们将共享一个连接池。