zoukankan      html  css  js  c++  java
  • establish connection

    慎用establish connection

    在一个Rails应用中连接多个数据库,我们常常这么做:

    Ruby代码  
    1. class Cookie < ActiveRecord::Base  
    2.     establish_connection :monitor_spider  
    3.     ...  
    4. end  

    这样,在使用Cookie.find等操作的时候,就会连接到database.yml中monitor_spider配置的数据库上操作。

    以前一直都这么用,没发现什么不妥。最近一个项目,由于启动的进程比较多,老是碰到数据库连接池链接获取超时的错误。通过MySQL Client用命令:show processlist;

    发 现数据库连接数量一直居高不下,轻轻松松就上2k+的连接。通过读Rails框架的connection_pool.rb文件代码,发现在各模型中用 establish_connection连接数据库会造成很大的问题。文件中类ConnectionHandler的 establish_connection方法代码如下:

    Ruby代码  
    1. def establish_connection(name, spec)  
    2.         @connection_pools[name] = ConnectionAdapters::ConnectionPool.new(spec)  
    3. end  
     对 应上面Cookie模型的配置,这里name的值会是Cookie。也就是说,有10个模型中使用了establish_connection配 置,@connection_pools中就会初始化10个ConnectionPool,如果每个ConnectionPool的pool size是20,那么应用运行的时候,将需要200(10 × 20)个数据库连接。而我的应用中有两类模型(连接到两个数据库),模型总数40+。按establish_connection的方式设置数据库连接, 那么mysql的连接轻易就被消耗完了。

    那要怎么处理呢?

    我现在的思路是自己来维护数据库连接池。

    首先,对ConnectionAdapters进行一下改造,将如下代码放到initializers中:

    Ruby代码  
    1. module ActiveRecord    
    2.   module ConnectionAdapters   
    3.     class ConnectionHandler  
    4.       def specified_establish_connection(name, spec)  
    5.         @connection_pools[name] = ConnectionAdapters::ConnectionPool.new(spec)  
    6.       end  
    7.          
    8.       def retrieve_connection_pool(klass)  
    9.         if klass.respond_to?(:pool_name)  
    10.           pool = @connection_pools[klass.pool_name]  
    11.           # ActiveRecord::Base.logger.info "pool: #{pool.inspect}"  
    12.           return pool if pool   
    13.         end  
    14.         pool = @connection_pools[klass.name]  
    15.         # puts pool.inspect  
    16.         return pool if pool  
    17.         return nil if ActiveRecord::Base == klass  
    18.         retrieve_connection_pool klass.superclass  
    19.       end  
    20.     end  
    21.   end  
    22. end  

    在environment.rb中事先连接建立数据库连接池:

    Ruby代码  
    1. #specified pool  
    2. config =  YAML::load(File.open("config/database.yml"))  
    3. %w(monitor_center monitor_spider).each do |pool_name|  
    4.   spec = config[pool_name]  
    5.   adapter_method = "#{spec["adapter"]}_connection"  
    6.   ActiveRecord::Base.connection_handler.specified_establish_connection(pool_name, ActiveRecord::Base::ConnectionSpecification.new(spec, adapter_method))   
    7. end  
     在模型中,定义方法pool_name:
    Ruby代码  
    1. class TaskStat < ActiveRecord::Base  
    2.   def self.pool_name;"monitor_spider";end  
    3.   ...  
    4. end   
    5.   
    6.   
    7. class TaskInfo < ActiveRecord::Base  
    8.   def self.pool_name;"monitor_center";end  
    9.   ...  
    10. end  

    这样,TaskStat就会用monitor_spider pool,TaskInfo会用monitor_center pool。同时整个应用就只有三个ConnectionPool(外加默认的ActiveRecord::Base的)

    通过这样的改造之后,效果明显,现在show processlist一般只有200~300的连接数。

  • 相关阅读:
    生成一个签章(用java.awt画一个签章) 并添加到pdf 公章处
    数字转字符串的处理
    Mybatis .xml编译常识
    聚合查询|F查询Q查询
    表查询
    FBV与CBV
    伪静态|虚拟环境|form表单
    数据增删改查|路由层
    django基础 链接数据库|静态文件配置
    WEB框架初学
  • 原文地址:https://www.cnblogs.com/qinyan20/p/3643130.html
Copyright © 2011-2022 走看看