繁体   English   中英

确保Rails和Sidekiq不会超过最大数据库连接

[英]Ensure max database connections is not exceeded with Rails and Sidekiq

我正在使用带有单线程Rails应用程序的Nginx和Phusion Passenger。 这是捕获。 在该应用程序中,我使用多线程sidekiq来执行一些后台作业。 通常在我的database.yml中,我只需要将池值设置为1.这是一个例子:

default: &default
  adapter: mysql2
  encoding: utf8
  collation: utf8_unicode_ci
  pool: 1
  username: username
  password: password
  host: localhost

原因是因为每个tcp套接字连接打开,当http请求通过该套接字进入时,nginx将接收请求并将信息传递给乘客。 Passenger检测到它的Rails应用程序,它产生一个Rails实例,它将响应转换为html,然后发送回nginx,然后传回给客户端(浏览器)。因此对于每个乘客实例,我只需要一个数据库连接,使用单线程Rails应用程序。

但是在我的sidekiq.yml中,我将并发设置为5:

:concurrency: 5 

这意味着对于每个乘客机架实例,我将有由sidekiq处理的5个并发线程加上主应用程序的一个连接,即一个乘客实例的总共6个数据库连接。

当我查看乘客状态时,我注意到max_pool_size设置为6:

----------- General information -----------
Max pool size : 6

那么这是否意味着乘客不会同时产生超过6个Rails实例? 如果是这样的话,这是否意味着我的数学是正确的:6(实例)* 6(数据库连接:5为sidekiq,1为主app)= 36(我的rails应用程序可以同时处理的总数据库连接)。

现在我的mysql数据库配置为处理151个最大并发连接。

SHOW VARIABLES LIKE "max_connections";
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 151   |
+-----------------+-------+

我只是想确保我的数学是正确的乘客,铁路和sidekiq。

首先,您的Sidekiq流程和您的Web服务器(在您的情况下,Passenger)是分开的。 Passenger的线程池大小对您的Sidekiq并发性没有影响; 相反,您的Sidekiq配置指定单独的并发。 所以,我们将分别考虑这两个:

乘客

ActiveRecord数据库池值是Web进程将在所有线程中使用的数据库连接数。 如果您的Passenger服务器设置为多进程模式,则Web进程的最大连接数为db pool size * passenger pool size 另一方面,如果你在多线程模式下设置它(我建议如果可能),你的最大连接只是db pool size (乘以许多进程正在运行;例如,Puma默认运行)两个进程最多包含15个线程,因此在这种情况下最大连接数为30)。

因此,如果您使用的是多线程模式,则池大小为1是绝对不够的 - 您至少需要与预期的线程一样大的池。 在多进程模式中, 1 可能有效,但我怀疑它是否真的值得从默认值5消失,直到遇到问题。

Sidekiq

Sidekiq总是以多线程模式运行(你可以在技术上运行多个进程,但我认为你不是)。 因此,如上所述,您希望连接池至少与线程数一样大。 这可能意味着您在技术上需要两个不同的db池值值,具体取决于Rails env是为Passenger启动还是为Sidekiq启动 - 请参阅Sidekiq repo上的此问题此有用的Heroku指南 ,了解有关如何使用的更多信息解决这个问题

综上所述

不要忘记,除了上述所有内容之外,您可以轻松地让多个服务器都运行相同的Rails应用程序,但只有一个数据库具有一个连接限制。 如果您在多实例模式下运行Passenger,最多有6个进程,请将数据库池大小设置为5,然后每个Web服务器节点最多使用30个连接。 如果它正在运行Sidekiq服务器,那么添加5。 您可能不需要多个Sidekiq服务器,因此4个Web节点@30个连接+一个Sidekiq进程@ 5个连接= 125个最大连接,完全在您的MySQL连接限制内。

我再次回顾了Passenger文档,虽然上面的答案回答了这个问题,但我想补充一点细节:

  • HTTP客户端通过TCP向Nginx发送请求
  • 加载到Nginx的Phusion Passenger检查请求是否应由Passenger处理。 如果是,请求将发送到Passenger Core。
  • 使用负载平衡规则的乘客核心确定应将请求转发到哪个进程。
  • Passenger核心还负责应用程序生成:如果它确定有更多的应用程序进程是必要的或有益的,那么它将根据用户配置的限制进行:核心永远不会产生比用户配置的最大值更多的进程。
  • 客运核心还有监测和统计数据:乘客记忆统计和乘客身份
  • 如果应用程序进程崩溃,则会重新启动应用程序进程。
  • 如果您没有将其配置为向联合站(一种监控Web服务)发送数据,则UstRouter处于空闲状态并且不会消耗资源
  • Watchdog监控Passenger Core和UstRouter。 如果它们中的任何一个崩溃,它们将由Watchdog重新启动。

    passenger-memory-stats将验证上述三个进程以及衍生的机架应用程序:

 ------ Passenger processes ------ PID VMSize Private Name --------------------------------- 18355 419.1 MB ? Passenger watchdog 18358 1096.5 MB ? Passenger core 18363 427.2 MB ? Passenger ust-router 18700 818.9 MB 256.2 MB Passenger RubyApp: myapp_rack_rails 24783 686.9 MB 180.2 MB Passenger RubyApp: myapp_rack_rails 

乘客状态显示max_pool_size为6.也就是说,乘客核心最多会产生6个机架应用程序:

----------- General information -----------
Max pool size : 6
App groups    : 2
Processes     : 3

如另一个答案所述,ActiveRecord数据库池值是Web进程将在所有线程中使用的数据库连接数。

但由于我使用的是在多进程模式下设置的免费Passenger服务器,因此我的Web进程的最大连接数是db pool size *乘客池大小。 因此,由于乘客池大小为6,如果我的数据库池大小为1,则为6 * 1 = 6.这将是6个最大数据库连接。

Sidekiq始终以多线程模式运行。

如果有人想使用sidekiq,他们必须配置他们想要运行的线程数或使用默认值(25)。 如果他们正在使用数据库(可能)然后没有遇到连接超时错误,他们将需要在其数据库池中至少具有与sidekiq线程一样多的连接。 目前,他们必须在两个不同的位置配置这两个值,数据库池在database.yml中用于ActiveRecord,而sidekiq连接可以通过命令行或sidekiq yml文件。 这是一个问题,因为当您修改需要修改两个值的一个值时很难记住。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM