编写一个多租户Rails 3应用程序,以便在Heroku上进行部署

我正在构建一个用于在Heroku上部署的Rails 3应用程序,我想知道是否有关于如何在我的模型中处理多租户的任何建议。 半年前,有一个相关问题( #3776593 )发布在这里,但没有得到很多答案。 我还看过Guy Naor关于使用Rails编写多租户应用程序的演讲 ,但似乎3个提议的解决方案中有2个不适用于Heroku。 我将链接到这些,但新的Stackoverflow用户限于2个超链接。

我还遇到了以下工具:

  • http://samuel.kadolph.com/2010/12/simple-rails-multi-tenancy/
  • http://blog.codecrate.com/2011/03/multitenant-locking-down-your-app-and.html

只是想知道你是否有使用多租户gem或简单轨道多租户gem的经验。 似乎最简单的解决方案是简单地将belongs_to放在我需要在账户下的所有模型上,但我真的很想知道你在现实世界中使用了什么!

这些方法的范围从“无共享”(通常意味着每个租户一个数据库)到“共享所有内容”,这通常意味着每个表都包含来自许多租户的行。 频谱(下图)可以通过隔离程度,成本(每个租户的成本)以及灾难恢复的简易性进行细分。

  • 每个租户一个数据库; 成本最高,隔离度最高,恢复最简单。
  • 每个租户一个架构; 其他两个之间的成本,良好的隔离,相当容易的恢复,但恢复通常会降低其他租户的性能。
  • 在租户之间共享表格; 最低成本,最低隔离(共享表),难以进行灾难恢复(恢复通常意味着为每个表恢复一些行)。 恢复通常会使其他租户“大量”降低性能。

所有这些都在某种程度上是平台特定的。 当dbms禁止查询访问多个数据库时,“每个租户一个数据库”具有最高的隔离度。 但是某些平台允许跨多个数据库进行查询。

MSDN有一篇不错的文章可以达到最高点: 多租户数据架构 。

但如果你只限于Heroku,你必须选择Heroku支持的选项。 我不知道这些选项可能是什么,但我知道你最好不要在开发中使用SQLite。 Heroku部署将在PostgreSQL上运行; 你需要针对PostgreSQL进行开发。

作为多租户gem的作者,我显然有偏见,但我真的相信这是一个很好的解决方案! gem的目标是简化这种常见的应用程序需求,并使其实现变得微不足道。

“旧学校”替代方案是使用rails对象链接来确保所有查询都通过关联的父级完成。 这种方法的问题在于您的租户对象成为has_many关联的倾倒场所。

class Tenant has_many :users end # query for users in the current tenant current_tenant.users.find params[:id] 

多租户gem通过确保生成的所有查询自动识别当前租户来解决此问题。 它还确保创建新记录并自动分配给当前租户,这样您就不需要添加任何特殊的before_save回调。

例如:

 Multitenant.with_tenant current_tenant do # queries within this block are automatically # scoped to the current tenant User.all # records created within this block are # automatically assigned to the current tenant User.create :name => 'Bob' end 

我即将开始这个冒险(实现小型铁路应用程序的多租户),在做研究时我偶然发现了这个SOpost。

令人惊讶的是,没有人提到RyanB使用Heroku支持的PostgreSQL模式实现MT的精彩截屏。

以下是截屏video的链接http://railscasts.com/episodes/389-multitenancy-with-postgresql 。

概念:

在rails app中,我们可以为pg连接设置搜索路径

  connection.schema_search_path = "schema1, schema2, ..." 

如果在schema1找到相应的表,则将在schema1上执行任何后续操作。 否则,它会搜索schema2中的表,依此类推。 与您的整个应用程序架构(包括租户)一起使用将是公开的,通常的做法是在公共架构中使除租户之外的所有表都为空。

新租户注册:

将after_create函数添加到租户模型以为新租户创建新架构,并将所有(加载schema.rb)应用表(租户除外)创建到此新架构中。

用户:

当用户访问subdomain1.myapp.com时,从租户表中查找此子域的架构,并将连接搜索路径设置为“schema1,public”并对用户进行身份validation。

请注意,我的目的只是为了涵盖解决方案背后的概念。 有关实际解决方案,请参阅RyanB的截屏video。