如何创建具有共享表结构的多租户数据库?

我们的软件目前运行在 MySQL 上。所有租户的数据都存储在同一个架构中。因为我们使用的是 RubyonRails,所以我们可以很容易地确定哪些数据属于哪个租户。然而,当然也有一些公司担心他们的数据可能被泄露,所以我们正在评估其他解决方案。

到目前为止,我看到了三种选择:

  • 多数据库(每个租户都有自己的数据库——几乎相当于每个客户一个服务器)
  • 多模式(在 MySQL 中不可用,每个租户在共享数据库中都有自己的模式)
  • 共享模式(我们当前的方法,可能在每一列上都有额外的标识记录)

多模式是我的最爱(考虑到成本)。然而,创建一个新帐户和进行迁移似乎非常痛苦,因为我必须遍历所有模式并更改它们的表/列/定义。

问: Multi-Schema 似乎是为每个租户设计的略有不同的表——我不想这样。是否有任何 RDBMS 允许我使用多模式多租户解决方案,其中表结构在所有租户之间共享?

附注: 我说的“多”是指超级“多”(10.000 + 租户)。

73623 次浏览

但是有一些公司呢 他们担心自己的数据可能 所以我们正在评估 其他解决办法。

这是不幸的,因为客户有时会产生一种误解,认为只有物理隔离才能提供足够的安全性。

有一篇有趣的 MSDN 文章,标题为 多租户数据体系结构,您可能想查看一下。这就是作者如何处理对共同方法的误解:

A common misconception holds that 只有物理隔离才能提供 适当的安全级别 事实上,使用共享 方法也可以提供强有力的数据 安全,但需要使用更多 复杂的设计模式。

关于技术和业务方面的考虑,本文简要分析了某种方法在哪些方面可能比另一种方法更为适当:

数量、性质和需要 你希望服务的所有租客影响 中的数据架构决策 不同的方式。下面的一些 问题可能会使你偏向于 另一些则可能采取孤立的方法 使你倾向于更多地分享 接近。

  • 你希望有多少潜在的租户? 你可能无处可去 几乎能够估计 预期的权威使用,但 从数量级的角度思考: 你是在为 几百个房客? 几千个? 几十个 成千上万? 更多? 你越大 期望您的租户基础是, 更有可能你会考虑 一个更加共享的方法

  • 您希望平均租户的数据占用多少存储空间? 如果你期望部分或全部租户 存储非常大量的数据, 单独的数据库方法可能是 最好。(事实上,数据存储 要求可能会迫使你采用 分离数据库模型。如果是这样, 它将更容易设计 应用程序的方式从 比移动到 稍后使用单独的数据库方法。)

  • 您希望平均租户支持多少并发最终用户? 数字越大,越多 采取更加孤立的方法 将满足最终用户的要求

  • 您是否期望提供任何针对租户的增值服务,例如 作为每个租户的备份和恢复 这种服务更容易 通过一个更加孤立的 进场


更新: 进一步更新预期租户数量。

对于大多数(如果不是所有的话)场景,预期的租户数量(10k)应该不包括多数据库方法。我认为您不会喜欢维护10,000个数据库实例,并且每天必须创建数百个新实例的想法。

仅从这个参数来看,似乎共享数据库、单模式方法是最合适的。事实上,每个租户只需要存储50Mb,而且不会有针对每个租户的附加组件,这使得这种方法更加合适。

上面引用的 MSDN 文章提到了三种处理共享数据库方法的安全考虑的安全模式:

当您对应用程序的数据安全措施有信心时,您将能够为客户提供一个 服务水平协议,它提供强有力的数据安全保证。在您的 SLA 中,除了保证之外,您还可以描述您将要采取的确保数据不受损害的措施。

更新2: 显然,微软的家伙们移动/制作了一篇关于这个主题的新文章,原来的链接不见了,这是新的一个: 多租户 SaaS 数据库租赁模式(向 Shai Kerer 致敬)

我的经验(尽管是 SQLServer)是多数据库的方法,每个客户机都有自己的数据库。因此,尽管我没有 mySQL 或 RubyOnRails 的经验,但我希望我的输入可以增加一些价值。

原因包括:

  1. 数据安全/灾难恢复。每个公司的数据都是与其他公司完全分开存储的,这样可以降低数据泄露的风险(想象一下,如果你引入了一个代码错误,这意味着有些东西错误地查看了其他客户端的数据,而它不应该这样做) ,如果一个特定的数据库被破坏,可以最小化对一个客户端的潜在损失。给客户带来的安全利益甚至更大(增加了额外的副作用!)
  2. 可伸缩性。从本质上讲,你需要将数据分区以提高可伸缩性——例如,数据库可以放在不同的磁盘上,你可以让多个数据库服务器联机,并更容易地移动数据库以分散负载。
  3. 性能调优。假设您有一个非常大的客户端和一个非常小的客户端。使用模式、数据量等可能变化很大。如果需要,您可以更容易地为每个客户进行调整/优化。

我希望这能提供一些有用的信息!还有更多的原因,但我的大脑一片空白。如果它反弹回来,我会更新:)

编辑:
自从我发布了这个答案,很明显,我们谈论的是10,000多个租户。我的经验是在数百个大型数据库中——我不认为10,000个独立的数据库对于您的场景来说太容易管理了,所以我现在不赞成在您的场景中使用多数据库方法。特别是现在很清楚,您所说的每个租户的数据量都很小!

无论如何,把我的答案保留在这里,因为它可能对其他在类似船上的人(租户较少)有一些用处

下面是 Salesforce.com 上关于如何实现多租户的白皮书链接:

Http://www.developerforce.com/media/forcedotcombooklibrary/force.com_multitenancy_wp_101508.pdf

它们有1个巨大的表 w/500字符串列(Value0、 Value1、 ... Value500)。日期和数字以字符串的形式存储,以便可以在数据库级别将它们转换为其本机类型。元数据表定义了数据模型的形状,每个租户可以是唯一的。还有用于索引、关系、唯一值等的附加表。

为什么这么麻烦?

每个租户都可以在运行时自定义自己的数据模式,而不必在数据库级别进行更改(alter table etc)。这绝对是一个困难的方法来做这样的事情,但是非常灵活。

正如您所提到的,每个租户一个数据库是一个选项,并且确实有一些更大的权衡。它可以在较小的规模(如个位数或租户数量低于10个)上运行良好,但除此之外,它变得更难管理。两者都只是迁移,但也只是为了保持数据库正常运行。

每个模式模型不仅对每个模式都有用,尽管仍然在所有租户之间运行迁移会变得困难,而且在1000个模式中 Postgres 可能会遇到麻烦。

更具可伸缩性的方法绝对是将租户随机分布,存储在同一个数据库中,但是跨不同的逻辑碎片(或 桌子)。根据您的语言,有许多库可以帮助您解决这个问题。如果您正在使用 Rails,那么有一个库来执行租户 acts_as_tenant,它可以帮助确保您的租户查询只提取那些数据。还有一个 gem apartment——尽管它使用了模式模型,但它确实有助于跨所有模式的迁移。如果你正在使用 Django 有一个数字,但其中一个更流行的似乎是跨 模式。所有这些在应用程序级别都有更大的帮助。如果您直接在数据库级别上寻找更多的东西,西塔斯专注于使这种类型的 多重租约分片在 Postgres 中更加开箱即用。