如何设计一个多租户的Node.js应用程序?

6

目前我面临一个技术决策,个人无法自行找到解决方案。

我正在开发一个多租户数据库。

结构如下:

  • 有一个核心数据库保存特定租户的数据和关系
  • 有多个租户数据库实例(从核心数据库的查询中确定应该连接哪个租户ID)
  • 每个租户都在单独的数据库实例上(在单独的服务器上)
  • 每个租户都有特定的数据,其他租户不能访问这些数据
  • 每个数据库最好是MySQL(但如果有更好的选择,我可以考虑建议)
  • 后端使用koa框架编写
  • 核心数据库和租户数据库的模型不同
  • 每个租户数据库的最大表可能达到100万条记录(没有审计)
  • 乐观地说,租户数量可能增长到50个

项目的其他数据:

  • 所有项目数据都可供所有者使用
  • 每个客户端将为其自己的租户提供数据
  • 每个租户都有自己的网站
  • 每个租户的数据库结构相同
  • 该项目主要是一个物流服务,其数据针对每个不同的地区进行分隔

问题:

这是设计多租户架构的正确方法,还是应该重新设计架构?

如果可以使用多服务器的多租户-是否有首选的工具/技术堆栈应该完成?(很想更具体地了解此事

最好使用ORM。我目前正在尝试使用Sequelize,但在早期阶段就遇到了问题(多个数据库不能共享相同的模型,管理多个连接)。

理想目标是能够添加其他租户而不需要进行太多的额外配置。

编辑: - 数据库当前托管在Azure上,但如果需要,我们希望它们可以迁移走。


目前来看,您的问题还无法回答,因为您构建的应用程序类型缺乏足够的上下文信息。多租户背后的设计决策受各种因素的驱动,例如预期租户数量、预期数据量、每个租户的变更灵活性等。 - James
我会尝试添加更多信息以澄清。无论如何,谢谢 :) - alogins
https://medium.com/@mohamedsameer72/how-we-build-the-multi-tenant-saas-product-using-node-postgres-sequelize-c66a085a42ce - Mohamed Sameer
2个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
6
存在一些在多租户架构中构建数据结构的方式。 很难说哪种选择更好,但我会尽力用我的一点知识来帮助你。 第一种选择:将数据库分割到分布式服务器中,例如每个租户都有自己完全隔离的数据库服务器。 这可能是不错的选择,因为我们可以确保租户数据的安全性,确保其他租户永远看不到其他租户的数据。 在这种情况下,我看到了一些问题。考虑成本,我们可能需要为每个客户端和软件许可证提高成本,具体取决于您的环境。考虑devops,我们将需要一个复杂的策略来为每个新租户创建和部署一个新实例。 第二种选择:分离数据库,我们有一个服务器,我们在其中为每个租户创建单独的数据库。 如果您需要为每个客户提供隔离,则经常使用此选项,因为我们可以为每个数据库关联不同的登录、权限等。 其他一些缺点:每个数据库都需要一个不同的连接池,必须在所有数据库之间复制更新,没有资源共享(除非使用弹性数据库池),并且您需要跨所有数据库使用多个备份策略,以及一个复杂的devops策略来部署和创建新的租户。 第三种选择:单独的模式,这是实现多租户架构的良好策略,我们可以共享一些资源,因为所有内容都在同一个数据库中,但使用的模式是不同的,每个租户都有一个单独的模式。这使您甚至可以自定义特定的租户而不影响其他人。并且您只需要支付一个数据库的费用,从而节省成本。 其中一些缺点:您需要在每个模式中复制所有数据库对象,因此对象数量可能无限增加,必须在所有模式之间复制更新,数据库的连接池必须维护每个租户(或凭据集)的不同连接,每个租户都需要一个不同的用户(存储在服务器级别),并且您必须独立备份该用户。 第四种选择:行隔离。 在此选项中,所有内容都是共享的,服务器、数据库和模式,所有租户的数据都在同一个数据库的同一个表中。它们区分的唯一方式是基于表级别存在的TenantId或其他列。 另一个好处是您将不需要一个复杂的devops策略,并且如果您正在使用SQL Server,则我知道,存在一个称为行级安全性的资源,以便您仅获取已登录用户具有权限的数据。 但是,在这种情况下,如果有数千个用户同时访问数据库,您将需要一些方法来实现良好的可伸缩性。 因此,您需要考虑您的情况以及您的系统将如何增长,以选择最佳选项。

还有一些其他选项,但问题实际上无法回答,因为几乎没有关于用户正在构建的应用程序类型的上下文。 - James
3
是的,James,如果没有更多的上下文,我们无法帮助我们的朋友,但是我可以尝试提供一些选项来澄清他的想法。 - Nicolas Takashi

0

对我来说看起来很好。

我认为瓶颈在于每个租户都在单独的DB服务器或DB实例上。这意味着您需要为每个租户保持单独的连接池,或者根据租户为每个请求创建新连接。尝试使用任何概念,可以为所有租户(命名空间、模式或仅为某些特定租户表名称添加租户特定前缀)拥有一个DB连接。

但是,如果您需要将租户的DB分开,例如由于不同的备份策略、资源限制等,则无法这样做,并且必须为每个租户管理单独的连接池。这也取决于您将有多少租户。数十个,数千个?

我还建议您在应用程序中缓存租户-> DB映射,而不是每次从核心数据库查询它。


一开始大约是2/3,但可能会增长到50。 - alogins

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