我有一个现有的Java EE 6应用程序(在Glassfish v 3.1中部署),并且希望支持多个租户。 我目前在我的应用中使用的技术/ API是
EJB(包括EJB计时器服务)
JPA 2.0(EclipseLink)
JSF 2.0
JMS
JAX-RS
我也打算使用CDI
据我所知,添加多租户支持仅影响持久层。 我的问题:有人做过吗? 转换应用程序的步骤是什么? 这会影响持久性以外的其他层吗?
将会有大量的租户,因此,所有数据都将驻留在同一数据库模式中。
这个问题假定多租户是一个完全定义明确的术语。 它不是。 相互之间存在许多程度的分离,安全性和其他方面的权衡,许多编码方法使所有这些分离或简化或变得更加困难。
除了Damo用户提供的内容外,强烈建议您参考此文档
请提供有关您的问题和其他所需信息的完整信息。
问题已经表明,将有大量租户,并且所有数据应该/可以驻留在同一数据库模式中。 我认为这足够具体,可以提出几种方法(一种或两种)。
对不起,没有得到。 您需要什么信息?
持久层
从持久层开始。完成此操作后,向上滚动整个体系结构。
您提议的架构将具有一个标识租户的ID(例如TenantId)。每个表将具有此ID。在所有查询中,您都必须确保TenantId与登录的用户的TenantId相匹配。
这样做的困难在于这是一个非常手工的过程。
如果您将Hibernate用作JPA提供程序,那么可以使用一些工具来解决此问题。即休眠过滤器。
这些通常用于限制对多租户模式的访问(更多信息,请参见此处和此处)
我没有使用过EclipseLink,但是它确实对Multi-Tenancy也有很好的支持。 DiscriminatorColumn看起来与Hibernate Filters非常相似。
服务层
我假设您正在将JAX-RS和JMS用于服务层。如果是这样,那么您还需要考虑如何传递tenantId并验证您的租户。您将如何阻止一个租户访问另一个租户的REST服务?对于JMS也是一样。
UI层
您将必须在UI中将您的登录信息连接到为Filter / Discriminator设置TenantId的Bean(Hibernate或Eclipselink)。
面向消息。
如果您选择消息传递作为战略方法并在JMS周围重构(如有必要)业务逻辑,则其他选择仍然可行并在本地适用。
使用这种方法,您可以在现有(单租户)系统中支付特定的固定成本(重构)。然后,您可以应用各种程度的复杂性,从简单的分片(@Geziefer基于id的关联)到全面的共享核心模式+扩展的特定于租户的方案方法,而不会影响系统体系结构和其他重构。
您将进一步通过消息传递层(应用路由器,过滤器,特殊处理路径等)对系统数据流进行正交控制。
[按要求编辑]
M.T.明确暗示了信息的方向。但是,作为一个普遍的问题,我们正在研究扩展接口和丰富数据流。根据基于API的方法,您需要在所有必需的接口(例如方法)中仔细注入适当的租户判别式。基于消息的消息(或基于上下文的API方法)允许使用规范的(稳定的)接口(例如message.send()),同时还允许使用显式的专用数据流。如果不在表上切换到基于消息的主干,则强烈建议您考虑在API中注入统一上下文(例如" RequestContext")参数。这个扩展可以满足您将来所有的专业需求。
在共享内存架构和多核环境中基于消息的架构的好处是额外的好处。
您能详细说明一下吗? JMS或面向消息的系统如何帮助我进行多租户?
@alphazero我同意Theo。 JMS与多租户有什么关系?
消息,Pete,不是JMS。 JMS,因为他已经使用过它。我不同意MT仅是持久性问题。该逻辑同样适用于您的整个域,但是您会注意到除了涉及数据库之外,您还有其他事情。至于为什么要发送消息,请参阅上面的帖子编辑。
可以采用多种方法,具体取决于您要实现的分离级别以及要支持的并发租户数量。在极端情况下,您可以为每个租户创建一个新的架构,从而确保数据库级别的数据隔离。对于大多数实际目的,通过为域模型中的每个实体分配tenant_id并维护外键约束,对数据进行逻辑分区通常就足够了。当然,这意味着您可能希望始终将当前会话的tenant_id传递给每个查询/查找器方法,以便它可以基于此限制数据集。您需要通过在URL中输入不属于他们的租户ID(或实体ID)来确保用户无法访问其他租户的数据。
告诉我们有关不同租户的数量以及分离和定制的程度。
如果您的租户数量很少,我建议创建一个可定制的"白标"产品。这使您有机会为一个租户创建一些特定的东西,而不会过于复杂。另外,将每个租户的应用程序分开可以帮助您进行维护。我们是针对具有多个不同租户的产品执行此操作的。
如果您有很多租户,那么这当然不再可行。我们做了相同产品的通用版本。然后,我们要做的就是在登录后通过ID区分租户,从而将数据与其他人分开。但是,就更改应用程序或其中的层而言,没有任何事情要做,ID就是分离数据所需的全部,并且工作流通过具有不同的Bean实例或其他受管理对象而自动分离。
将没有特定于租户的自定义。但是,"白标"方法将如何工作?你到底什么意思?关于tenant-id:因此,我要做的就是将tenant ID列包含到每个JPA实体中。我想租户ID必须是主键的一部分,对吗?
在这种情况下,白色标签表示您创建的软件没有任何徽标,特殊设计和客户特定功能。然后,您可以为每个租户自定义它,使其看起来像他们自己的。在您的情况下,当您说不需要客户化时,您只需要将每个租户的数据明确分开即可。为此,您有几种可能,一种是将租户ID添加到某些(肯定不是全部)JPA实体。它不一定必须位于主键中(因为我更喜欢具有技术性的主键),所以您也可以向某些根对象添加外键并从其继续。