【问题标题】:Database connection pooling数据库连接池
【发布时间】:2011-11-01 19:33:28
【问题描述】:

我在 Heroku 上用 Sinatra 和 jQuery 创建了一个小型聊天应用程序。它只是在用户提交消息时将消息插入数据库。并且每 2 秒下载一次新消息。经过几分钟的测试,它停止工作,我收到了一封来自 heroku 的电子邮件:

嗨,

我们注意到 gisekchat 应用有大量连接 打开共享数据库。我们不得不限制连接数 由于性能原因,共享数据库。你也可以吗 减少与共享数据库的总连接数或移至 专用数据库?

您似乎没有利用连接池 并为来自的每个请求打开一个到数据库的新连接 你的应用程序。

谢谢, -克里斯

这是支持提交消息的动作(接收非常相似):

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

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

【问题讨论】:

    标签: ruby database sinatra


    【解决方案1】:

    是的,这是真的,每次“发送”后发送时,您确实是在打开与数据库的新连接。

    所以你需要改变它。一种可能是,全局打开连接:

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

    这应该在您初始化 $dbname... 变量之后但在您使用任何路由之前完成。

    但是,如果您使用的是模块化 sinatra 版本,而不是经典版本,您可以使用

    声明一个实例变量
    attr_accessor :con
    

    并在应用启动前对其进行初始化。

    【讨论】:

      【解决方案2】:

      Robustus 已经成功了一半 创建实例变量将为您的类的每个实例创建一个连接。

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

      我创建了一个名为“q”的 ruby​​ 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)。

      【讨论】:

      • 是的,如果线程安全是您需要实现的目标,这似乎是正确的,但这通常是您只能在模块化版本中执行的操作,而不是经典版本 (afaik)
      • 从示例代码的外观来看,我们正在处理一个 sinatra 应用程序。我不确定,但我认为每个请求都来自 heroku 免费托管上的一个新线程。 “模块化版本”是什么意思?
      • 编写 sinatra 应用程序有两种不同的版本。经典的,其中“主”文件包含路线和操作,例如没有实例变量,并且是模块化的,您可以在其中实现一个继承自 Sinatra::Base 的类
      • 实例变量仍然可用,不是吗?如果你不继承 Sinatra::Base,范围会更广
      • jacob,实际上我现在已经对其进行了测试,如果您在经典环境中声明了 get ... end 块之外的实例变量,您将无法在 get ... end 块中使用它。
      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-10-23
        • 2014-04-09
        • 2015-08-09
        • 2012-08-03
        • 2013-01-09
        • 2010-12-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多