具有SQL Server 2016 Shard的多租户系统是否应该通过每个租户通过单独的数据库进行租户隔离?


12

给定用例:

  • 租户数据不应串扰,一个租户不需要另一租户的数据。
  • 每个租户都可能具有较大的历史数据量。
  • SQL Server托管在AWS EC2实例中。
  • 每个租户在地理位置上都相距遥远。
  • 有意使用第三方可视化工具,例如PowerBI Embedded
  • 预计数据量会随着时间增长
  • 系统的成本受到限制。
  • 没有24/7生产DBA,解决方案必须可维护
  • 解决方案应该能够水平缩放。
  • 租户总数少于50

推荐的体系结构是什么,此用例是否有参考实现?我相信许多人可能已经在企业软件开发中遇到了这个问题。

我认为这与处理多租户数据库体系结构中越来越多的租户不同。在该问题中提到的用例处理的租户数量更多,这与只有极少数(50)的大租户不同。提到的体系结构可能是这里的解决方案,这是我想进一步了解的。

Answers:


16

分片的陷阱是应用程序必须知道要查询哪个分片。通常,这是通过在客户端上分片来完成的。我将改编我的旧博客文章之一作为答案。

在为许多客户构建应用程序时,有两种常见的方法来设计数据库:

  • 选项A:将所有客户端放在同一数据库中
  • 选项2:为每个客户端建立一个数据库

将所有客户端放入同一数据库

很简单:只需在架构顶部添加一个Client表,添加一个ClientUsers表以确保人们只能看到他们自己的数据,然后就可以了。

这种方法的好处:

简化架构管理。开发人员部署新版本的应用程序时,只需在一个数据库中进行架构更改。不用担心不同的客户不同步或版本错误。

性能调整更容易。我们可以在一个地方检查索引的使用情况和统计​​信息,轻松实现改进,并立即在所有客户中看到效果。对于成百上千的数据库,即使最小的更改也可能难以协调。我们可以检查过程高速缓存的内容,并确定哪些查询或存储过程是整个应用程序中最密集的,但是如果每个客户端使用单独的数据库,则在不同执行计划中汇总查询使用的时间可能会更困难。

易于构建外部API。如果我们需要为外部人员授予对整个数据库的访问权限以构建产品,那么如果所有数据都在单个数据库中,则我们可以更轻松地进行操作。如果API必须处理来自多个服务器上多个数据库的数据分组,则它会增加开发和测试时间。(另一方面,“多台服务器”开始暗示对一个数据库到所有规则的所有场景的限制:一个数据库通常意味着我们所有的负载只会影响一个数据库服务器。)借助PowerBI,将每个人都放在一个数据库中将使连接管理变得更加容易。

轻松实现高可用性和灾难恢复。如果我们只需要担心一个数据库,那么管理数据库镜像,日志传送,复制和集群非常非常简单。我们可以快速构建基础设施。

将每个客户端放入自己的数据库或碎片中

您仍然需要一个客户端列表,但现在它成为一个目录-对于每个客户端,您还可以跟踪其所在的分片。启动时,您的应用程序查询此表并将其缓存在RAM中。当它需要客户端的数据时,它直接连接到该分片(数据库和服务器)。

这种方法的好处:

单客户端还原更容易。客户是不可靠的肉袋。(除了我,它们是可靠的肉袋。)他们有各种各样的“糟糕”时刻,他们想将所有数据恢复到某个时间点,如果数据混杂在一起,那将是后方的巨大痛苦。同一表中的其他客户端数据。在单客户端数据库场景中进行还原非常容易:只需还原客户端的数据库即可。没有人受到影响。

数据导出更容易。客户喜欢获得数据。他们希望安全地知道自己可以随时获取数据,避免了可怕的供应商锁定情况,并且希望自己进行报告。将每个客户端的数据隔离到自己的数据库中后,我们可以简单地给他们一个自己的数据库备份的副本。我们不必构建数据导出API。

简化多服务器可伸缩性。当我们的应用程序需要的功能超出我们从单个服务器获得的能力时,我们可以在多个服务器之间划分数据库。我们还可以在地理上分散负载,将服务器放置在亚洲或欧洲以更接近客户。

简化每个客户端的性能调整。如果某些客户使用不同的功能或报告,我们可以为那些客户建立一套专门的索引或索引视图,而无需增加每个人的数据量。诚然,这里存在一些风险–通过允许客户端之间的架构差异,我们使代码部署的风险有所提高,而性能管理也更加困难。

简化安全管理。只要我们已正确锁定每个数据库只有一个用户的安全性,我们就不必担心客户端X访问客户端Y的数据。但是,如果我们仅对所有人使用一个登录名,那么我们还没有真正解决这个问题。

维护窗口更简单。 在客户遍布全球的全球环境中,如果我们可以按组或区域进行维护,则使客户脱机进行维护更加容易。

哪一个适合您?

没有一个正确的选择:您必须了解您自己公司的优缺点。让我们以我的两个客户为例。

甲公司擅长硬件性能调整。他们确实非常擅长将硬件的最后性能发挥到极致,并且他们不介意在12-18个月的周期内更换其SQL Server硬件。(他们每4-6个月刷新一次Web服务器!)他们的致命弱点是极高的合规性和安全性要求。他们具有难以置信的审计需求,对他们而言,在单个服务器,单个数据库上实施防弹控制比在多个服务器上的数千个数据库中管理这些要求要容易得多。他们选择了一个数据库,一台服务器和许多客户端。

公司2擅长开发实践。对于他们来说,管理模式更改和跨数千个数据库的代码部署并不是问题。他们有世界各地的客户,他们正在全天候为这些客户处理信用卡交易。他们需要能够在地理上分散负载的能力,并且他们不想每隔12-18个月就更换一次服务器。他们为每个客户选择了一个数据库,随着他们开始为离岸客户在亚洲和欧洲部署SQL Server,它正在获得回报。


“就您而言,使用PowerBI,将每个人都放在一个数据库中将使管理连接变得更加容易”。目前,PowerBI Embedded不具有行级安全性,因此将每个租户都放在一个数据库中会引起对该用例的某些疑问,请参阅:community.powerbi.com/t5/Developer/…,鉴于此信息,请您重新表述这或建议替代方案或纠正我的理解?
DS

另外,“将每个客户端放入自己的数据库或碎片中”您能否在此详细说明这两个建议之间的区别
DS

我只是说必须部署到多个数据库并没有听起来那么糟。在2017年,我们提供了许多选项,可以非常轻松地将更改部署到1、5或900个数据库。而且,当您有特定客户的例外情况时,通常可以以不干扰通用代码的方式将这些例外情况引入这些数据库。
亚伦·伯特兰

5

我还没有在其他答案中看到另一个考虑因素。

具有允许在一个数据库中容纳多个租户的设计,将在以后提供灵活性。如果以后需要加载/扩展/安全/地理位置要求,建议租户应该有一个单独的数据库,可以通过在新实例上还原当前数据库来创建该数据库。其他租户的数据仍然受到任何适当机制的保护。在时间允许的情况下,可以从旧数据库和新数据库中逐一删除现已过时的数据。

反之则不成立。整合许多单租户数据库将需要大量工作。


4

即使打破了规范化*,也使多租户模型容易得多的一种做法是在每个表上都为该租户添加一个列。您可以将其称为TenantID。这样,针对数据库运行的每个查询都可以根据每个表上的TenantID进行过滤,并且您可以使用数据库分区为每个租户隔离数据,并通过对齐分区来加快查询速度。通过这种方式将所有租户都放在一个数据库中要容易得多。

*它并不总是破坏规范化,但是可以。例如,如果您有PersonPersonAddress表。该Person表将TenantID, PersonID作为主键。该PersonAddress表将TenantID, PersonID, AddressTypeID作为我建议的主键。

通常情况下就PersonID足够了,因为您可以将其连接回Person表以查找Tenant。我建议您继续TenantID使用每个后续表,即使在使用更细的键时也是如此。

据我了解,将任何可以从其他数据派生的信息转发到表中被认为违反了规范化。但是也许使用瘦键只是一种最佳实践。


谢谢,我同意这个建议,并在此基础上补充一点,我想提一下,此字段TenantID必须是整数类型,而不是GUID,我们为提高性能而采用了这种方法。
DS

3
但是,即使您选择将TenantID携带到子表中(不必这样做),更宽的键也不意味着标准化被“破坏了”。就像选择GUID而不是IDID(一个较宽的键)一样,它不会破坏规范化,也不会选择一个更宽的自然键而不使用替代项。
亚伦·伯特兰
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.