【问题标题】:Multi tenancy support in Java EE 6Java EE 6 中的多租户支持
【发布时间】:2011-06-25 14:28:06
【问题描述】:

我有一个现有的 Java EE 6 应用程序(部署在 Glassfish v 3.1 中)并希望支持多个租户。我目前在我的应用中使用的技术/API 是

  • EJB(包括 EJB 定时器服务)
  • JPA 2.0 (EclipseLink)
  • JSF 2.0
  • JMS
  • JAX-RS
  • 我也打算使用 CDI

据我所知,添加多租户支持只影响持久层。我的问题:以前有人做过吗?转换应用程序的步骤是什么?这会影响除持久性之外的其他层吗?

会有大量租户,因此所有数据都将驻留在同一个数据库架构中。

【问题讨论】:

  • 这个问题假定“多租户”是一个定义明确的艺术术语。它不是。有许多程度的分离、安全性和诸如此类的相互权衡,并且有许多编码方法使它们变得更容易或更难。
  • 除了达摩用户提供的以外,强烈推荐你参考这个document
  • 请提供您的问题和其他您想要的完整信息。
  • 问题已经表明会有大量租户,并且所有数据都应该/可以驻留在同一个数据库模式中。我认为这已经足够具体,可以提出一些方法(一种或两种)。
  • 抱歉,没听懂。您需要什么信息?

标签: java jakarta-ee java-ee-6 multi-tenant


【解决方案1】:

持久层

从持久层开始。完成后向上滚动整个架构。

您提议的架构将有一个标识租户的 ID(例如 TenantId)。每个表都有这个 ID。在所有查询中,您必须确保 TenantId 与登录用户的 TenantId 匹配。

这样做的困难在于这是一个非常手动的过程。

如果您使用 Hibernate 作为您的 JPA 提供程序,那么有一些工具可以帮助您解决此问题;即Hibernate Filters

这些通常用于限制对多租户架构的访问(请参阅 herehere for some more

我没有使用过 EclipseLink,但它看起来也像 has good support for Multi-Tenancy。 DiscriminatorColumn 看起来与 Hibernate Filters 的概念非常相似。

服务层

我假设您将 JAX-RS 和 JMS 用于服务层。如果是这样,那么您还需要考虑如何传递tenantId 和authenticate 您的租户。你将如何阻止一个租户访问另一个租户的 REST 服务? JMS 也是如此。

界面层

您将不得不将您在 UI 中的登录连接到为过滤器/鉴别器设置 TenantId 的 Bean(Hibernate 或 Eclipselink)。

【讨论】:

    【解决方案2】:

    请告诉我们不同租户所需的分离和定制的数量和程度。

    如果您的租户数量很少,我建议创建一个可定制的“白标”产品。这使您有机会为一个租户创建一些特定的东西,而不会使事情变得过于复杂。此外,将每个租户的应用程序分开有助于您进行维护。我们为具有少数不同租户的产品这样做。

    如果您有很多租户,这当然不再实用。我们做了同一产品的通用版本。然后我们所做的就是在登录后通过 id 来区分租户,从而将数据与其他数据分开。但是,在更改应用程序或其中的层方面仍然没有任何事情可做,id 是分离数据所需的全部内容,并且工作流通过具有不同的 bean 实例或其他托管对象自动分离。

    【讨论】:

    • 不会有特定于租户的自定义。但是,“白标”方法将如何发挥作用呢?你到底什么意思?关于租户 ID:这意味着我所要做的就是将租户 ID 列包含到每个 JPA 实体中。我猜租户 ID 需要是主键的一部分,对吧?
    • 白标意味着在这种情况下,您创建的软件没有任何徽标、特殊设计和客户特定功能。然后你为每个租户定制它,让它看起来像他们自己的。在你的情况下,当你说你不需要自定义时,你只需要清楚地分离每个租户的数据。为此,您有多种可能性,一种是将租户 ID 添加到某些(当然不是全部)JPA 实体。它不一定必须在主键中(因为我更喜欢使用技术主键),您还可以为某些根对象添加外键并从它们继续。
    【解决方案3】:

    您可以采用多种方法,具体取决于您想要实现的分离级别以及您想要支持的并发租户数量。在一个极端情况下,您可以为每个租户创建一个新模式,从而确保数据库级别的数据隔离。对于大多数实际目的,通过将tenant_id 分配给域模型中的每个实体并维护外键约束,通常就足以对数据进行逻辑分区。当然,这意味着您可能希望始终将当前会话的tenant_id 传递给每个查询/查找方法,以便它可以基于此限制数据集。您需要通过在 url 中输入不属于他们的租户 ID(或实体 ID)来确保用户无法访问其他租户的数据。

    【讨论】:

      【解决方案4】:

      以消息为导向。

      如果您选择消息传递作为战略方法并围绕 JMS 重构(如有必要)业务逻辑,那么其他选项仍然可行且适用于本地。

      使用这种方法,您需要在现有(单租户)系统中支付特定的固定成本(重构)。然后,您可以应用各种复杂程度的方法,从简单的分片(@Geziefer 基于 id 的关联)到完整的共享核心模式 + 扩展租户特定模式方法,而不会影响系统架构和额外的重构。

      您将通过消息传递层进一步对系统数据流进行正交控制(应用路由器、过滤器、特殊处理路径等)

      [根据请求编辑]

      在 M.T. 中没有任何东西。这明确暗示了信息导向。但作为一个普遍问题,我们正在研究扩展接口丰富的数据流。根据基于 API 的方法,您需要在所有必需的接口(例如方法)中小心地注入适当的租户判别式。基于消息(或基于上下文的 API 方法)允许规范(稳定)接口(例如 message.send())并且同时允许显式专用数据流。如果切换到基于消息的主干不在桌面上,强烈建议您考虑在 API 中注入统一的上下文(例如“RequestContext”)参数。这个单一的扩展应该涵盖您未来的所有专业化需求。

      【讨论】:

      • 在共享内存架构和多核环境中基于消息的架构的好处是额外的好处。
      • 能否详细说明。 JMS 或面向消息的系统如何帮助我实现多租户?
      • @alphazero 我同意西奥的观点。 JMS 与多租户有什么关系?
      • 消息传递,Pete,而不是 JMS。 JMS,因为他已经在使用它。我不同意 MT 仅仅是坚持的问题。该逻辑也适用于您的整个域,但您会注意到除了涉及数据库之外您还有其他问题。至于为什么发消息,请参阅上面的帖子编辑。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-02
      • 1970-01-01
      • 2014-01-17
      相关资源
      最近更新 更多