English 中文(简体)
客户网站的最佳数据库策略(Ruby on Rails)
原标题:
  • 时间:2008-12-08 15:02:44
  •  标签:

我建立了一个适合小众市场需求的不错网站系统。过去一年以来,我一直使用Capistrano 将该软件的副本部署到我的网页服务器并销售这些网站。

我意识到这些网站唯一的区别就是数据库、CSS 文件和一小部分用于个别客户的图形设计所使用的图片。

其他一切都一模一样,或者应该是...现在我已经部署了大约20个这样的网站,将它们全部更新相同的代码变得很麻烦。而且这个问题只会变得更糟。

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

看起来处理数据库有两种方式:

  • using multiple databases, one for each client
  • using one database, with a client_id field in each table, and an extra client table

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

但是,每次想要迁移数据库时都必须为数十个或数百个不同的数据库运行 rake db:migrate 将是一件麻烦的事情。显然,这可以通过脚本完成,但这并不好闻。

另一方面,每个客户在项目表中将拥有20K-50K个项目。当项目表中有50万或100万个项目时,我担心全文搜索的速度。即使在client_id字段上建立了索引,如果项目被分隔到不同的客户数据库中,我猜想搜索将更快。

如果有人对解决这个问题有经过研究的意见,我非常想听听。提前非常感谢...

约翰

最佳回答

使用单独的数据库有优点(包括您已列出的)。

  • Fulltext searches will become slow (depending on your server s capabilities) when you have millions of large text blobs to search.
  • Separating the DBs will keep your table indexing speed quicker for each client. In particular, it might upset some of your earlier adopting clients if you take on a new, large client. Suddenly their applications will suffer for (to them) no apparent reason. Again, if you stay under your hardware s capacity, this might not be an issue.
  • If you ever drop a client, it d be marginally cleaner to just pack up their DB than to remove all of their associated rows by client_id. And equally clean to restore them if they change their minds later.
  • If any clients ask for additional functionality that they are willing to pay for, you can fork their DB structure without modifying anyone else s.
  • For the pessimists: Less chance that you accidentally destroy all client data by a mistake rather than just one client s data. ;)

所有这些话说过之后,鉴于单个数据库解决方案,可能更好。

  • Your DB server s capabilities makes the large single table a non-issue.
  • Your client s databases are guaranteed to remain identical.
  • You aren t worried about being able to keep everyone s data compartmentalized for purposes of archiving/restoring or in case of disaster.
问题回答

感谢您的好评。我已经决定采用多数据库的方式。这对我来说是最简单的方式,因为我不必重新设计整个应用程序。

我要做的是在 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这样的URL将选择正确的数据库。

由于我在Mongrel前面使用了Apache作为代理,Apache将根据客户网站的URL向所有请求添加正确的client_id。因此,客户端ID实际上不会是用户看到的URL的一部分,它只会在Apache和Mongrel之间传递。我不确定我是否解释清楚了,但它可以工作并保持事情的清洁和简单。

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

有人认为这种方法存在问题吗?

约翰

我会选择单个数据库,使用客户端 ID - 您应该能够通过使用某种形式的基本模型和一个命名范围将任何操作限定在该客户端 ID 下来使重构变得不那么痛苦。

您可以使用索引库,例如Ferret或类似的东西,来处理全文搜索变慢的问题。这将成为一个问题,一旦单个客户端的数据库变得太大,您可能需要无论如何实施它。





相关问题
热门标签