Rails多租户架构,对多个租户进行范围访问

时间:2013-06-24 15:23:01

标签: mysql ruby-on-rails postgresql rails-postgresql multi-tenant

目前我们有一个单租户数据库架构,MySQL运行了100个数据库。我们使用Apartment gem在子域上切换数据库连接,所有都是花花公子!

但是,我们现在需要创建所谓的“Umbrella”客户端,它们可以访问我们现有客户端的所有数据。我不认为这对我们的单租户数据库架构是立即可行的(我查看它并查询多个MySQL数据库看起来很糟糕),所以我开始研究Postgres模式的不同实现。

我正在寻找一些建议:

  • 是否可以在Postgres中查询多个模式并以某种方式整理结果(寻找Rails实现)?我可以预见主键冲突的问题吗?

  • 以某种方式拥有一个新架构会更好吗? 表示/复制需要的模式组中的所有数据 被访问?它需要是实时的。

  • 如果是这样,可以在我当前的多个数据库中实现类似的功能 用MySQL设置? (尽量减少痛苦)

我担心使用数据库字段来实现MySQL中的多租户,因为数据安全/隐私对于这个产品来说是一件大事,而且开发人员错误的可能性很大。

4 个答案:

答案 0 :(得分:2)

尽管在我第一次出发时在Rails应用程序中找到了许多多租户的例子,但我找不到一个让我觉得完全舒服的例子。但我终于找到了一个我很满意的解决方案。

我开始使用'带有范围的多租户'railscast

http://railscasts.com/episodes/388-multitenancy-with-scopes

然后考虑使用本指南使用设计子域进行多租户工作:

https://github.com/plataformatec/devise/wiki/How-To:--Isolate-users-to-log-into-a-single-subdomain

但我并没有把它当作表面看法;我深深地了解了设计是如何运作的。

一旦我掌握了所有这些,我就为多租户宝石做好了准备:

https://github.com/wireframe/multitenant

但我并没有就此止步。 multitenant gem需要你说Multitenant.with_tenant只要你想要适当的东西,所以我创建了一个如下所示的TenantController:

  around_filter :scope_current_tenant

  def scope_current_tenant
    begin
      Firm.current = Firm.find_by_subdomain!(request.subdomain)
    rescue
      raise ActionController::RoutingError.new('Not Found')
    end

    Multitenant.with_tenant Firm.current do
      yield
    end

    ensure
      Firm.current = nil
    end
  end

然后我想要由租户确定范围的任何控制器都继承自TenantController而不是ApplicationController。这样我就不必在控制器的细节中记住任何东西,它“只是起作用”。开发人员唯一需要考虑的是“这是一个处理租户数据的控制器吗?”

虽然这仍然取决于开发人员正确地做了一些事情(继承自正确的控制器,在模型中说'acts_as_multitenant',但它在实践中效果很好。

答案 1 :(得分:1)

OBS:我不是一个Ruby人,所以我只能给你这个想法的PG方面。

使用PostgreSQL架构,您可以轻松管理它。只需为您拥有的每个租户创建一个模式,因此在您的应用程序中,当您需要更改租户时,您只需执行此操作:

SET search_path TO client1;

有了这个,当你查询一个表时,让我们说customer,你只需要在同一个连接上进行:

SELECT ... FROM customer ...;

而且,当您需要查询其他租户(不在search_path中)时,您可以使用架构查询该表:

SELECT ... FROM client2.customer ...;

您可以使用其他架构来存储公共信息,例如public架构,只需将其添加到search_path的末尾:

SET search_path TO client1, public;

答案 2 :(得分:1)

只是通过高级方法来解决这个问题。

您可以创建一个pg view表来访问此数据(尽管 比访问数据库本身要慢)。

然后,您希望表中有足够的唯一字段来创建复合键或复合键。 (那么你不必创建一个新的键列,只需一个索引)。因为Rails 3是ORM不可知的,所以你可以使用DataMapper(或者可能是新的ROM gem)来建立这个模型的连接。

如果您执行复合键,请意识到您可能必须在模型中显式定义* to_param *方法以将键构建为字符串。这是用于在您在网址中发送时解包:id。

您可以通过不同的Postgres用户设置对此视图的访问权限,然后使用Rails的多个连接功能为其创建模型。我们之前这样做是为了聚合来自多个表的数据,但对所显示的内容有一些限制,但我不明白为什么这不适用于您的用例。

另一种选择是,也许你可以使用Mongo作为“瞬态查询数据库”。 BSON会自动为您提供唯一的密钥。您可以创建基本上是SQL标量对象的对象。在这种情况下,不确定你是否想要写回原始数据库...但是你可以做到这一点。

底线IMO我认为最好的解决方案在于数据库方面,因为您使用的是多个数据库。在数据库层处理这些项似乎是最好的解决方案。

说完所有这些......这似乎也是一种过程气味。如果我按正确的方式阅读了问题,我认为在这种情况下你真正要做的是Hadoop的设计目的......实质上是相关数据的映射/减少(又称大数据分析)

祝你好运!

答案 3 :(得分:-3)

讨厌说出来,因为听起来你已经对你现有的系统投入了很多,但这听起来像是一个更适合NoSQL解决方案的工作。

具体来说,我正在考虑使用“无模式”键值数据库设计的MongoDB。这将使您能够基于密钥从数据库中提取数据并在软件中对其进行排序。 MongoDB还支持分片,它允许您在任意数量的数据库服务器上使用一个数据库,这听起来在您的应用程序中可以很好地工作。 http://www.mongodb.org/的文档可能值得一试。我不确定它是否适合你,但听起来它可以适用于你的应用程序。