是否选择多租户架构?

19

我需要做一个关于多租户的困难数据库设计决策,因为我的客户基于Web的CRM系统不断增长的分支数量,我正在积极维护。

早期我决定为每个分支使用独立的应用和数据库,因为这是满足三个具有不同数据和代码要求的分支的最简单方式。我还想避免在每个查询中管理租户ID,就像我在2007年构建的经典ASP(可怕)应用程序一样...太恐怖了。

但现在分支的数据需求正在收敛,并且随着业务的扩展,我需要能够快速推出新的分支并共享全局产品SKU。

由于所有分支的表和视图都是相同的,并且现在有更好的ORM工具来管理多租户应用程序,所以我想知道是否最好拥有多个分支共享的数据库。

考虑集中式数据库:

  • 全球产品SKU
  • 简化库存请购
  • 更容易备份
  • 只需部署一次,而不是每个分支都要部署

反对集中式数据库的考虑:

  • 使用单独的数据库更容易区分分支要求
  • 模块化部署(一个停机的分支不会影响所有分支)
  • 更难管理和开发共享的数据库
  • 我必须重新设计发票编号(由种子生成的序列)
  • 在任何地方都减少WHERE子句
  • 恢复一个出现问题的分支将对其他分支产生很多影响

未来分支数量不可能超过10个,目前只有3个。

在这方面具有实际经验的开发人员,在我的情况下,您会怎么做?保持应用程序和数据库分离,还是合并为一个巨大的系统?


编辑: 微软有一篇关于多租户的优缺点的精彩文章。 我应该注意到,分支之间的数据隔离并不是一个主要问题。


2
这篇微软的文章真是太棒了,我觉得非常有用。 - user529141
7
更新:经过三年的实践证明,使用分开的数据库是一个糟糕的决定,技术债务每天都在造成困扰。为了能够共享权限、库存单位(SKUs)和报告,并且只需要一次部署相同的代码,而不是十二次,现在我必须花费几个月时间重写代码并将实时数据移动到中央以集中各分支的数据。 - Petrus Theron
1
我在之前的工作中使用了分别为每个客户设置的不同数据库超过10年,从未考虑过合并它们。这种做法到底有什么问题?技术债务究竟如何每天影响我们?我敢打赌,我们已经解决了这些痛点。 - Aaron Bertrand
@AaronBertrand 当我几年前写下这个问题时,我的意思是同一家企业的不同分支。 - Petrus Theron
8个回答

7
咬紧牙关,将它们合并。在需要的地方添加您的租户ID,并更改查询。
对于自定义内容,请查看插件类型架构,允许您为特定客户端部署特定屏幕。
我们有一个软件产品,就是这样构建的。有时它部署在客户端站点上,有时我们托管它。就所有目的而言,使用具有客户端特定扩展的单个代码库要容易得多,而不是处理多个代码分支。
首先,当我们解决问题时,我们会为每个人解决问题。当然,如果我们破坏了它,我们就会破坏每个人,但这就是单元测试的作用。维护一组针对一个代码库的单元测试比维护它们针对多个分支要容易得多。
我们已经进行多租户超过10年了,我从未回头看过。一般来说,如果您已经注意到验证检索记录的人是否实际上被允许获取它,则查询并不那么不同。
我不同意Corbin提出的问题。关于版本控制的问题应该已经通过设置基于属性的安全结构来处理。这样,您可以通过用户或租户配置打开/关闭它们。此外,我发现很少有客户端A不想要客户端B要求的相同新功能。
关于数据混合的第二个问题也不是问题。只需查看salesforce.com或其他大型站点即可。他们绝对使用多租户架构,并且根据使用它们的客户端数量来判断,这似乎不是问题。这里的主要问题是能够向客户保证其数据已得到保护。

7
如果你只考虑10个分支,多租户似乎成本高而收益少。
多租户存在一些你没有提到的问题:
- 版本控制变得困难。客户X、Y和Z可能需要一个新功能,而客户A、B和C则不需要。多租户应用程序使得满足每个人的需求变得困难,特别是当一个新功能需要数据库模式更改时。这并非不可能,但更加困难。 - 一些客户对他们的数据与其他客户的数据混杂在同一个表中感到非常不舒服。即使我们知道更好的做法,它们仍然感觉像是安全风险。法律部门也不喜欢这样的情况。此外,如果你曾经为一个客户转储原始数据,那么共享数据库就需要小心谨慎了。
你可以通过更好的实践来消除一些痛点:
- 自动化部署。这应该使添加新客户或升级/降级现有客户变得更容易。数据库维护(备份、重建索引)也应该自动设置。 - 在中央数据库中存储共享数据(SKU、库存),并让每个应用程序实例直接访问它或通过服务访问它。
不要误解,我曾经工作过的一款最有趣的应用程序是多租户的。它可以带来巨大的好处,但你更可能在成千上万的客户中看到这些好处,而不是只有十个。

我强烈倾向于使用分离的数据库。问这个问题让我想起了我当初做出这个决定的原因。 - Petrus Theron

3
老实说,这是一个业务问题。在多租户设置中,您可以为较小的用户组提供更多定制功能,但需要更多的IT开销。也就是说,您需要更多的人和硬件(管理人员会读到:金钱),但能够提供更大的灵活性。
如果您处于一个巨大的Borg情况下,那么您将降低IT开销(同样,人员和物品,对于管理层来说是金钱),但您的最终用户将需要在其软件中承担较少的灵活性。所有的错误都是所有用户的问题,所以大的错误会很快被解决。然而,新功能也会影响所有用户,因此它们发生得更慢。
如果您个人有权做出这个决定,而业务只需听从您的话,或者您可以向管理层施加一些压力,我建议您自己问一系列关于您喜欢哪种情况的问题:
A)您是否希望有更多的人来管理这个,并分享薪水/责任? B)据您所知,是否会很快有第四个用户群? C)您想在这家公司呆多久?
如果您对前两个问题回答是肯定的,那么您可能想要选择多租户。

2
我在一个监管/法律原因下的环境中工作,我们必须将每个客户的数据保存在单独的数据库中。然而,有些信息必须共享,主要是与查找表相关的内容,用于确定哪个客户的URL对应哪个数据库。此外,客户可以选择拥有多个数据库,以便以某种逻辑方式分离其数据。因此,对于我们的每个产品,我们实际上有三种类型的数据库:
1. ApplicationData,它只有几个包含有关客户本身的信息的表,例如当通过特定URL访问时使用哪个MasterData数据库(见下文)以及哪些功能对该客户可用。每个产品只有一个ApplicationData,无论有多少不同的客户在使用该产品。
2. MasterData,其中包含特定于客户的信息,例如用户、角色和权限(在我们的情况下,aspnet_regsql创建的表在此处)。这里指定的权限包括哪些ClientData数据库对给定用户可用(见下文)。所有MasterData数据库(对于同一产品)的模式都相同。
3. ClientData,其中包含用户交互的数据。在一个产品中,这是客户可以根据大量标准搜索、创建报告等的数据。在另一个产品中,这包含了客户可以上传的动态数据,以便其他用户可以通过电话联系人进行调查等。对于同一产品的所有ClientData数据库,模式都相同。
现在,有一个警告:实际上,我们对MasterData和ClientData使用相同的模式,通常也使用同一个实际数据库。这是由于历史原因,因为允许客户拥有一个认证数据库(MasterData),对应多个ClientData数据库的能力是一个相对较新的功能,仅适用于我们的一个产品。此外,由于大多数客户只使用一个ClientData数据库,这种结构简化了部署。但是,在我们的项目中,MasterData和ClientData具有不同的实体模型下Entity Framework,并且我们必须确保MasterData和ClientData之间没有直接关系,例如外键。
这个设置对我们来说非常有效。一个主要优点是,在不同的服务器上放置不同的ClientData数据库没有问题。这对于负载平衡非常有帮助,并提供了一种自然的数据分区方式。如果客户愿意支付费用,我们可以为其提供专用的数据库服务器,从而为具有大量数据的客户提供帮助。
在这种情况下,还有一件事情真正帮助了我们,那就是Red Gate的工具,特别是Multi-Script、SQL Source Control和Schema Compare等工具。当我们升级某些内容并且模式发生变化时,我们必须将更改部署到所有相关的数据库中。这些工具节省了大量时间,已经超过了它们的成本。请注意,我与Red Gate没有任何关联,只是一个满意的用户。
编辑:(回应评论)
ApplicationData是每个产品的一个数据库。我们拥有的三个基于Web的产品使用相同的ApplicationData架构,因为它们记录基本相同类型的信息。然而,没有理由必须保持这种状态。ApplicationData数据库都在同一服务器上。ApplicationData中的一个表指向客户端MasterData的正确服务器和数据库名称,因此给定客户端的MasterData可以驻留在任何服务器上。
MasterData对于每个ClientData数据库都有服务器和数据库名称信息,因此数据库可以驻留在任何服务器上。实际上,目前我们只有两个生产数据库服务器用于这些产品。每个客户都有自己的MasterData。如果客户购买多个产品,则该客户的每个产品都有一个MasterData;如果客户已购买该功能(或请求定制开发此功能),则产品以其他方式进行交互(基本上通过Web服务)。给定产品的ClientData始终具有相同的架构。
因此,总之:
1. ApplicationData是每个产品的,恰好在每个产品中具有相同的架构。 2. MasterData是每个客户的产品。 3. 在产品中,一个客户有一个或多个ClientData实例。
我稍微简化了一下,只有我们的一个产品支持每个客户多个ClientData实例。对于第二个产品,这可能最终会被实现。对于第三个产品,作为一个功能毫无意义,可能仅保持不变。
希望这回答了你的问题!

很好的反馈。您能澄清一下您的“ApplicationData”、“MasterData”和“ClientData”数据库中哪些是在产品/客户端/服务器之间共享的吗? 作为一名小型开发人员,我还无法负担Red Gate的工具,尽管我渴望在我的频繁数据库冒险中使用它们。 - Petrus Theron
@FreshCode 编辑以回答您的问题。 - Andrew

1

如果我们谈论的是CRM,那么一个客户在多个数据库中的机会有多大?如果甚至有一丝可能性让你被要求在不同分支之间合并客户详细信息,那我肯定会选择一个集中式的数据库。


1

嗯,如果趋势是在不同分支之间共享信息和数据,那么最好有一个中央数据库。

否则,为了实现数据共享的能力,你将不得不经历比共享数据库所需的额外WHERE子句更糟糕的麻烦。

当然,你可以为每个分支设置一个数据库,并且作为需要共享的信息的集中存储,再增加一个额外的数据库(目前是第四个数据库)。尽管如此,你必须看看这种过度复杂化是否使其成为最佳或最糟糕的解决方案 :)


我对 NHibernate 不熟悉。如果一个中央 ASP.NET MVC 应用程序具有不同的 {branch} 参数,我应该如何透明地做到这一点? - Petrus Theron
你让我有点懵,NHibernate在这里起什么作用?我只是提供一个可能的方法建议,我没有使用过NHibernate。你能更明确地说明一下最后一个问题吗? - Sergi Papaseit
抱歉 - 我应该发布一个单独的问题。 - Petrus Theron

0

IMO去中心化正在成为可维护和可扩展设计的基石。我使用的唯一集中式数据库是用于安全认证,目前我正在将其发展为分散式数据库以进行授权。因此,所有授权都可以留在应用程序物理位置相同的边缘,无需网络遍历,因为授权不适合缓存。

从您特别关注同一应用程序的多个分支而不是真正不同的应用程序的角度来看,一个很好的选择是围绕种子处理过程(Entity Framework支持此功能)构建数据库,这将允许您仅将新分支代码部署到ASP.NET,然后在初始构建期间创建物理表的数据库,您轮询“受保护”的服务器并将所有所需数据转储到边缘服务器。

之后,如果要向主数据存储添加新产品并希望这些产品出现在每个边缘存储中,则需要设置一些复制设置。您可以通过直接复制数据库或查看Microsoft Sync框架等工具来实现此目的。


0

你可能今天认为只会有几个客户,但几年后你可能会意识到产品有潜力销售给数百个客户。如果发生这种情况,你会后悔使用单租户方法。

比较以下成本:

  1. 将生产系统从单租户转换为多租户,其中数据库填充了客户数据
  2. 开发一个多租户系统,即使您认为自己不需要这些好处

将生产系统转换是一项艰巨且非常昂贵的任务。尽管使用第二种方法最初可能会花费更多,但它确实为您提供了一个非常有价值的选项,以能够以低成本在未来添加更多客户。该选择权的价格可能值得支付。


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