基于客户端的网站的最佳数据库策略(Ruby on Rails)

时间:2008-12-08 15:02:45

标签: ruby-on-rails ruby database activerecord

我已经建立了一个很好的网站系统,以满足小型利基市场的需求。去年我通过使用Capistrano将软件副本部署到我的网络服务器来销售这些网站。

在我看来,这些网站的唯一区别是数据库,CSS文件以及用于个人客户端图形设计的一小组图像。

其他所有内容都完全相同,或者应该是......现在我已经部署了大约20个这样的站点,使用相同的代码让它们全部更新变得很麻烦。这个问题只会变得更糟。

我在想我应该重构这个系统,以便我可以使用一组已部署的ruby代码,通过传入请求的URL动态选择正确的数据库等。

似乎有两种处理数据库的方法:

  • 使用多个数据库,每个客户端一个
  • 使用一个数据库,每个表中包含一个client_id字段,另外还有一个“客户”表

多数据库方法对我来说是最简单的,因为我不必重构应用程序中的每个模型来将client_id字段添加到所有CRUD操作中。

但是,每次我想要迁移数据库时,必须为数十或数百个不同的数据库运行'rake db:migrate'会很麻烦。显然这可以通过脚本完成,但它闻起来不太好。

另一方面,每个客户在'items'表中都有20K-50K项目。当items表中有五十万或几百万个项目时,我担心全文搜索的速度。即使在client_id字段上有索引,我怀疑如果将项目分成不同的客户端数据库,搜索会更快。

如果有人对解决这个问题的最佳方法有了明智的意见,我非常希望听到它。非常感谢...

- 约翰

3 个答案:

答案 0 :(得分:4)

感谢您的好评。我决定采用多种数据库方法。这对我来说是最简单的方法,因为我不需要重写整个应用程序。

我要做的是在application_controller中添加一个before_filter,因此它适用于所有控制器......如下所示:

before_filter :client_db         # switch to client's db

然后,在application_controller.rb中,我将包含以下内容:

 def client_db
    @client = Client.find(params[:client_id]) 
    spec = Client.configurations[RAILS_ENV] 
    new_spec = spec.clone 
    new_spec["database"] = @client.database_name
    ActiveRecord::Base.establish_connection(new_spec) 
  end

然后,像example.com?client_id=12345这样的网址将选择正确的数据库。

由于我在Mongrel面前使用Apache作为代理,因此Apache会根据客户端的网站URL为所有请求添加正确的client_id。因此,client_id实际上不会成为用户看到的URL的一部分。它只会在Apache和Mongrel之间传递。我不确定我是否正确地解释了这一点,但是它起作用并使事情变得简洁。

如果我决定将来需要使用单个数据库,那么我可以重构所有代码。目前,这似乎是最简单的方法。

有人发现这种方法存在任何问题吗?

- 约翰

答案 1 :(得分:2)

使用单独的DB(包括您已经列出的DB)是有好处的:

  • 当您有数百万个大型文本blob要搜索时,全文搜索会变慢(取决于您服务器的功能)。
  • 分离数据库将使每个客户端的表索引速度更快。特别是,如果您使用新的大型客户端,它可能会使您早期的一些客户感到不满。突然之间他们的应用程序(对他们来说)没有明显的理由。同样,如果你的硬件容量不足,这可能不是问题。
  • 如果你放弃了一个客户端,那么打包他们的数据库比通过client_id移除所有相关行要简单得多。如果他们以后改变主意,同样可以恢复原状。
  • 如果有任何客户要求提供他们愿意支付的额外功能,您可以在不修改任何其他人的情况下分叉他们的数据库结构。
  • 对于悲观主义者:错误而不仅仅是一个客户的数据意外破坏所有客户数据的可能性较小。 ;)

所有这一切,单个数据库解决方案可能更好:

  • 您的数据库服务器的功能使大型单一表格成为无问题。
  • 保证客户的数据库保持一致。
  • 您并不担心能够将每个人的数据划分为存档/恢复或发生灾难的目的。

答案 2 :(得分:1)

我会使用客户端ID来访问单个数据库 - 您应该能够通过使用某种形式的基本模型来减少重构,并使用命名范围将任何操作范围限定为该客户端的ID。

您可以使用索引库(如Ferret)或其他类似的东西来处理全文搜索变慢的问题。无论如何,一旦单个客户端的数据库变大,这将成为一个问题,因此您可能需要以这两种方式实现。