在Heroku上部署多租户Rails 3应用的编写

13
我正在构建一个Rails 3应用程序,以在Heroku上部署,并想知道如何处理我的模型中的多租户问题是否有任何建议。半年前,这里发布了一个相关问题(#3776593),但没有得到太多答案。我还观看了Guy Naor关于使用Rails编写多租户应用程序的演示文稿,但似乎其中3个提出的解决方案中有2个在Heroku上无法工作。我会链接到这些内容,但新的Stackoverflow用户只能有2个超链接。
我还发现了以下工具:

我想知道你是否有使用过多租户 gem 或 simple-rails-multi-tenancy gem 的经验。在我看来,最直接的解决方案似乎是在所有需要属于某个账户的模型上添加 belongs_to 关联,但我真的很想知道你在实际世界中使用的是什么!


1
出于好奇,你最终是如何解决这个问题的? - kmurph79
3个回答

6
这些方法的范围从“不共享任何东西”,通常意味着每个租户一个数据库,到“共享所有东西”,通常意味着每个表包含来自多个租户的行。这个谱系(如下)可以通过隔离程度、成本(每个租户的成本),以及灾难恢复的易用性来分解。
  • 每个租户一个数据库;成本最高,隔离性最好,恢复最容易。
  • 每个租户一个模式;成本介于其他两者之间,隔离性好,恢复相当容易,但恢复通常会降低其他租户的性能。
  • 在租户之间共享表;成本最低,隔离性最差(共享表),灾难恢复困难(恢复通常意味着为每个表恢复一些行)。恢复通常会“大幅”降低其他租户的性能。
所有这些方法在某种程度上都是特定于平台的。“每个租户一个数据库”在DBMS禁止查询访问多个数据库时具有最高的隔离性。但是,某些平台允许跨多个数据库进行查询。
MSDN有一篇不错的文章,涵盖了重点:多租户数据架构
但是,如果您受限于Heroku,则必须选择Heroku支持的选项。我不知道这些选项可能是什么,但我知道您最好不要在开发中使用SQLite。Heroku部署将在PostgreSQL上运行;您需要针对PostgreSQL进行开发。

6
作为多租户宝石的作者,我显然有偏见,但我真的相信它是一个很好的解决方案!该宝石的目标是简化这个常见的应用需求,并使其实现变得微不足道。
“老派”的替代方法是使用Rails对象链接,以确保所有查询都通过相关的父对象完成。这种方法的问题在于您的租户对象变成了一个存放has_many关联的垃圾场。
class Tenant
  has_many :users
end
# query for users in the current tenant
current_tenant.users.find params[:id]

多租户宝石通过确保所有生成的查询自动了解当前租户来解决此问题。 而且它还确保新记录被创建并自动分配给当前租户,因此您不需要添加任何特殊的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

3
嘿,Ryan,为什么不利用默认作用域(default_scope)而使用Multitentant.with_tenant的方式呢? - rafamvc

2

我即将开始实现一个小型rails应用程序的多租户功能,并在研究过程中偶然发现了这篇SO文章。

令人惊讶的是,没有人提到RyanB的出色视频教程,该视频教程介绍了如何使用PostgreSQL模式实现MT,并且还受到Heroku的支持。

以下是视频教程链接:http://railscasts.com/episodes/389-multitenancy-with-postgresql

概念:

在rails应用程序中,我们可以为pg连接设置搜索路径。

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

如果在schema1中找到相应的表,则任何后续操作都将在该schema上执行。否则,它会在schema2中搜索表,以此类推。首先,您整个应用程序模式(包括租户)将位于public中,通常做法是在public schema中除了租户之外所有表都为空。

新租户注册:

向您的租户模型添加一个after_create函数,为新租户创建一个新的schema,并将所有(加载schema.rb)应用程序表(除了租户)创建到这个新的schema中。

用户:

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

请注意,我的意图只是涵盖解决方案背后的概念。有关实际解决方案,请参阅RyanB的视频教程。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接