Rails数据库连接池的工作原理

34

我正在学习Rails数据库连接池的概念。在Rails应用程序中,我定义了5个连接的池大小。

我的理解是:

  1. 当服务器启动时,Rails会自动创建在database.yml文件中定义的n个连接。在我的情况下,它将创建5个连接,因为池大小是5。

  2. 每次http请求需要访问数据库时,Rails将使用连接池中可用的连接来处理请求。

但我的问题是,如果我同时发出1000个请求,大多数请求将无法访问数据库连接,因为我的连接池大小仅为5。

我的上述理解是否正确?

谢谢。

2个回答

35

目的:
数据库连接不是线程安全的,因此ActiveRecord为每个线程使用单独的数据库连接。

限制因素:
总数据库连接数受您使用的数据库服务器(例如Posgres:默认通常为100或更少),应用程序服务器的配置(可用进程/线程数)和Active Record的配置限制: 连接池 默认为5。

池大小:
Active Record的池大小是针对单个进程的。一个线程从这个池中使用一个连接,然后自动释放它。 (除非你自己生成了一个线程,那么你就必须手动释放它)。如果您的应用程序在多个进程上运行,则每个进程都会有5个数据库连接。如果您的服务器同时收到1000个请求,则它将把这些请求分配到这些连接中,当它已满时,其余请求会等待它们的机会。

阅读更多信息:
https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/ConnectionPool.html


1
如果我的Web服务器是单进程,则只会有一个连接池;如果它是多进程,则连接池的总数将等于进程数。对吗? - user2274074
1
是的,没错。但通常情况下,应用程序应该基于多个进程/线程。 - Raza
如果同时运行两个进程,比如进程“A”和进程“B”,那么将会有两个独立的连接池。假设进程“A”创建了两个线程,并且这些线程需要访问数据库,那么这些线程将使用哪个连接池呢?是由进程“A”创建的连接池还是进程“B”创建的连接池? - user2274074
当然,这个过程A实际上是由池5处理的,这意味着每个连接都在同一进程的不同线程上可用。 - Raza
如果我的服务器是多线程的,那该怎么办?我想在这种情况下,我只会有一个连接池,无论同时有多少个HTTP连接。 - user2274074
显示剩余2条评论

14

是的,来自文档:

连接池同步线程对有限数量的数据库连接的访问。基本思路是每个线程从池中检出一个数据库连接,使用该连接,并将连接还回。ConnectionPool完全是线程安全的,并确保只要正确遵循ConnectionPool的协议,连接不能被两个线程同时使用。它还处理线程数大于连接数的情况:如果所有连接都已经被检出,并且一个线程尝试检出连接,则ConnectionPool会等待直到其他某个线程检入连接。

来源:http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/ConnectionPool.html

如果您使用类似独角兽(Unicorn)这样的HTTP服务器:

在Unicorn中,每个进程建立自己的连接池,所以如果您的DB池设置为5并且您有5个Unicorn工作进程,则最多可以有25个连接。但是,由于每个独角兽工作进程一次只能处理一个连接,因此除非您的应用程序在内部使用线程,否则每个工作进程实际上只使用一个数据库连接。


请查看此链接,它指出每个工作进程都会创建一个新的连接池。 - user2274074
1
如果您使用像独角兽这样的东西:在独角兽中,每个进程都建立自己的连接池,因此如果您的数据库池设置为5并且您有5个独角兽工作进程,则最多可以有25个连接。但是,由于每个独角兽工作进程一次只能处理一个连接,所以除非您的应用程序在内部使用线程,否则每个工作进程实际上只会使用一个数据库连接。 - Laurens
乘客怎么样?我正在使用带有Nginx的Passenger。 - user2274074
我猜乘客和独角兽很相似。乘客可以创建多个工作进程(应用实例)。 - user2274074
1
您可以使用'passenger-status'进行检查,更多信息请阅读:https://www.phusionpassenger.com/library/walkthroughs/basics/ruby/process_management.html - Laurens
谢谢,我会检查并回复你。 - user2274074

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接