2009-11-02 42 views
3

感谢您的时间第一......在谷歌,github和这里搜索之后,并且对大词(分区/分片/ fedorate)感到困惑,我认为我必须描述我遇到的具体问题,问问周围。如何使ActiveRecord与传统的分区/分片数据库/表一起工作?

我公司的数据库中有大量的用户和订单交易,于是将通过各种方式的数据库和表,一些描述如下:

way    database and table name  shard by (maybe it's should be called partitioned by?) 
YZ.X   db_YZ.tb_X     order serial number last three digits 
YYYYMMDD.  db_YYYYMMDD.tb    date 
YYYYMM.DD  db_YYYYMM.tb_ DD    date too 

的基本概念是,数据库和表分隔acording到现场(并不是主键),并且数据库太多,表格太多,因此,为每个数据库写入或奇迹般地生成一个database.yml配置文件,而为每个表格创建一个模型是不可能的,或者至少不是最佳的解决方案。我研究了drnic的魔术解决方案,datafabric,甚至是活动记录的源代码,也许我可以使用ERB生成database.yml,并在过滤器中执行数据库连接,也许我可以使用named_scope动态决定查找表的名称,但更新/创建操作被限制为“self.class.quoted_table_name”,以便我不能轻易地解决问题。我甚至可以为每个表格生成一个模型,因为它的数量最多可达30个。

但这只是不干!

我需要的是像下面的DSL一个干净的解决方案:

class Order < ActiveRecord::Base 
    shard_by :order_serialno do |key| 
     [get_db_config_by(key), #because some or all of the databaes might share the same machine in a regular way or can be configed by a hash of regex, and it can also be a const 
     get_db_name_by(key), 
     get_tb_name_by(key),   
     ] 
    end 
end 

可有人微启我吗?任何帮助将不胜感激~~~~

回答

1

第二种情况(只有数据库名称发生更改)使用DbCharmer很容易实现。您需要在DbCharmer中创建您的own sharding method,这将返回基于密钥的连接参数哈希。

另外两起案件中不支持马上,但可以很容易地添加到您的系统:

  1. 你实现,知道如何在分片dabatase处理数据库名称拆分方法,这将给你有能力做shard_for(key)调用你的模型来切换数据库连接。

  2. 您添加一个方法是这样的:

    class MyModel < ActiveRecord::Base 
        db_magic :sharded => { :sharded_connection => :my_sharding_method } 
    
        def switch_shard(key) 
        set_table_name(table_for_key(key)) # switch table 
        shard_for(key)      # switch connection 
        end 
    end 
    
  3. 现在你可以使用你的模型是这样的:

    MyModel.switch_shard(key).first 
    MyModel.switch_shard(key).count 
    

    ,并考虑到你有shard_for(key)通话效果从switch_shard方法返回,你可以这样使用它:

    m = MyModel.switch_shard(key) # Switch connection and get a connection proxy 
    m.first      # Call any AR methods on the proxy 
    m.count 
    
+0

感谢您的详细解决方案,它非常有用。然而,似乎有一个致命的问题:set_table_name是一个类方法,它的影响是整个类的,我无法将其范围限定在特定的对象。 这就是为什么我正在考虑更多内部的东西,比如“为每个表奇迹般地生成一个模型”,这似乎在您的魔法解决方案中使用(仍在努力了解DbCharmer的来源)。 如果可能,我想将它添加到DbCharm中,但还有另外一个致命的问题,DbCharmer没有单元测试......那么我怎样才能避免在这个过程中破坏某些东西呢? – Utensil 2011-10-22 09:59:57

+0

DbCharmer支持范围内的连接切换。您始终可以执行MyModel.on_db(:foo){...}或MyModel.switch_shard(key){...},它只会切换块中的连接。至于测试,有一个单独的项目与规格(几乎100%覆盖宝石的代码):https://github.com/kovyrin/db-charmer-sandbox – kovyrin 2011-10-23 15:51:21

1

如果你想要那个特定的DSL,或者与遗留分片背后的逻辑相匹配的东西,你将需要挖掘到ActiveRecord并编写一个gem来给你那种能力。您提到的所有现有解决方案都不一定是根据您的情况编写的。您可能可以根据自己的意愿弯曲任意数量的解决方案,但最终您可能必须编写自定义代码才能获得您所需的内容。

+0

感谢您的回答!我确实挖掘了AR的来源,并且挖掘了我找到的不同解决方案的来源。我完成了所有这些工作,以便为AR编写我自己的插件。最接近的解决方案之一是sharded_database插件,尽管它不支持表分区......我猜“class << self; set_table_name; end”可能会让我更改每个AR实例的表名。但成本,我不知道。并且每次更改数据库连接,都会放弃池的所有好处...通过提问,我试图寻找类似情况下的人... – Utensil 2009-11-05 09:27:28

+0

如果碰巧有一个优雅的设计,触摸很少并侵入AR,我将不胜感激的光... – Utensil 2009-11-05 09:32:27

1

听起来像,在这种情况下,你应该考虑不使用SQL。

如果数据集很大并且可以表示为键/值对(稍微去规范化),那么您应该查看一下couchDB或其他noSQL解决方案。 这些解决方案速度快,可完全扩展,并且基于REST,因此很容易进行增长和备份和复制。

我们都已经用相同的工具解决了所有的问题(相信我,我也尝试了)。

切换到noSQL解决方案然后重写activeRecord会容易得多。

+0

感谢您的答案!开放解决方案总是很棒〜CouchDB是一件好事。我*爱* erlang。不幸的是,在我的情况下,非SQL不是一种选择。 MySQL数据库和许多其他C/C++程序是真正的和严重的业务中的大多数,我只是试图用rails来与他们交谈。 – Utensil 2009-11-05 09:19:11