数据库连接池

4
我在Heroku上使用Sinatra和jQuery创建了一个小型聊天应用程序。当用户提交消息时,它会简单地将消息插入到数据库中,并且每2秒下载新的消息。经过几分钟的测试后,我收到了来自Heroku的一封邮件:
“你好,
我们注意到gisekchat应用程序连接到共享数据库的连接数量很多。出于性能原因,我们不得不限制共享数据库的连接数。您可以减少对共享数据库的总连接数,或者转移到专用数据库吗?
似乎您没有利用连接池,并为应用程序的每个请求打开了新的数据库连接。
谢谢, -Chris”
这是支持提交消息的操作(接收操作非常相似):
post '/send' do
  con = con = PGconn.connect($dbhost, 5432, "","",$dbname, $dbuser, $dbpass)
  con.exec("insert into messages(usr, msg, date) values('#{params[:usr]}','#{params[:msg]}', now())")    
end

我该如何修改它以启用连接池?

3个回答

6

是的,这是真的,每次“发送”后都会打开一个到数据库的新连接。

所以你需要进行更改。一种可能的方法是全局打开连接:

 $con = PGconn.connect($dbhost, 5432, "","",$dbname, $dbuser, $dbpass)

在你初始化$dbname变量之后,但在使用任何路由之前,请完成此操作。

然而,如果您正在使用模块化sinatra版本而不是经典版本,则可以声明一个实例变量。

attr_accessor :con

在应用程序启动之前,需要先初始化它。


4

Robustus已经完成了一半的工作,创建一个实例变量将为你的类的每个实例创建一个连接。

你需要的是一个线程安全的数据存储API,它将使用互斥锁来处理对连接对象的访问。这是Rails中ActiveRecord使用的控制机制。

我创建了一个名为“q”的Ruby gem,提供了一个简单的机制来实现这一点。该gem位于以下位置: https://github.com/jacobsimeon/q

像这样安装它 git clone https://github.com/jacobsimeon/q

然后将其添加到初始化应用程序的任何文件中:

require 'q/resourcepool'

然后在初始化期间创建您的数据存储:

class DataConnection < ResourcePool
  def create_resource
    PGConn.connect(@config)
  end
end
@datasource = ResourcePool.new(your_connection_info_here)

然后,您可以使用 @datasource 来执行针对数据库的命令。
post '/send' do
  @datasource.exec(standard_postgres_params)
end

如果您有兴趣走这条路,请在Github或Twitter上联系我(两者都是@jacobsimeon)。

是的,那似乎是正确的,如果线程安全是您需要实现的内容,但这通常只能在模块化版本中完成,而无法在经典版本中完成(据我所知)。 - robustus
从示例代码的外观来看,似乎我们正在处理一个sinatra应用程序。我不确定,但我认为每个请求都通过heroku免费托管上的新线程进行处理。 你所说的“模块化版本”是什么意思? - jacobsimeon
实例变量仍然可用,不是吗?如果您没有子类化Sinatra :: Base,则范围将更广。 - jacobsimeon
根据我的经验,范围不会涉及路由,但也许是我做错了什么。 - robustus
1
Jacob,实际上我现在测试了一下,如果你在经典环境中声明一个实例变量,它会超出 get ... end 块,你将无法在 get ... end 块内使用它。 - robustus
显示剩余2条评论

1
我曾使用过“经典”的Sinatra应用程序,并通过声明类变量(例如@@db_connection)获得了相同的结果。这始终使用相同的连接,并且对我有效。

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