2019独角兽企业重金招聘Python工程师标准>>>

适用于:应用程序体系结构--软件即服务(SaaS)
关于设计的多租户应用程序三种不同的方法来创建数据架构.

0.什么叫做多租客

  多租客一般适用于软件开发,以指示在其中一个应用程序的运行实例同时服务多个客户端(房客)体系结构。这是非常常见的SaaS(http://baike.baidu.com/view/1559138.htm)解决方案。隔离信息(数据、自定义项等)有关的各种租户在这些系统中是一个特别的挑战。存储在数据库中的每个租客所拥有的数据称为多租客的数据,我们将侧重的。

1.分离数据库(Separate Databases)

每个租户的数据保存在一个物理上独立的数据库实例。JDBC连接会特别指出每个数据库。一个通用的应用程序的方法是定义一个JDBC连接池,当前登录的用户关联的"租客标识符"来选择JDBC连接.
好处:可以轻松地扩展应用程序的数据模型(稍后讨论)以满足住户的个别需求,而且在失败时从备份恢复租客的数据是一个相对简单的过程。
坏处:导致更高的设备成本,以及维护和备份租客数据方面的成本。
相对较高的硬件,维护成本使它适合于愿意额外支付增加的安全性和可定制性的客户。例如,在银行或医疗记录管理等领域的客户往往有很强的数据隔离的要求,甚至不得不不为每个租客提供具有其自己单独的数据库。

2.共享数据库,彼此独立的Schema(Shared Database, Separate Schemas)

每个租客有它自己的表,可以理解为为每个租客分表.每个租客在共享的数据库中具有其自己单独的一组表.
数据库中的Schema详见:http://baike.baidu.com/view/1374119.htm?hold=syn

当客户第一次订阅该服务时,资源调配子系统为租客创建一组离散的表,并将它与租客的Schema关联。您可以使用 SQL 创建命令创建一个架构,并授权用户帐户来访问它。
例如,在 Microsoft SQL Server 2005:CREATE SCHEMA ContosoSchema AUTHORIZATION Contoso;

应用程序然后可以创建和访问表内的租户的架构使用SchemaName.TableName公约:
CREATE TABLE ContosoSchema.Resumes (EmployeeID int identity primary key,Resume nvarchar(MAX));

创建Schema后,它是作为租客帐户的默认Schema设置:
ALTER USER Contoso WITH DEFAULT_SCHEMA = ContosoSchema

租客帐户可以访问其默认架构内的表,只是通过指定TableName,而不是使用SchemaName.TableName.这种方式,一组 SQL 语句可以给所有的租客使用来访问其自己的数据,例如:SELECT * FROM Resumes

优点:这样是容易实现的一种方法,租户可以与单独的数据库方法一样扩展数据模型。(创建的表但一旦不符合需求,租客可添加,修改表)

这种方法提供了中等程度的逻辑数据隔离安全,虽然比不上作为一个完全独立的数据库,但却可以在每个数据库服务器支持大量的租户。

缺点:数据出现故障时是难以恢复某租客。如果每个租客有其自己的数据库,则还原单个租户的数据意味着简单地从最近的备份还原数据库。而这个方法则意味着用备份的数据还原整个数据库,而不管在同一数据库上的每个租客的数据是否遭到损失。因此,要还原单个客户的数据,数据库管理员可能需要将数据库还原到一个临时的服务器,然后将客户的表导入到生产服务器上 — — 一个复杂和可能很耗时的任务。

3.共享数据库,共享Schema(Shared Database, Shared Schema)

这个方法就是最简单的一种了.每个表使用租客的一个标识符.所有租户都共享一组相同的表,一个租客 标识符ID 将每个租客与它拥有的行相关联.

优点:最低硬件和备份成本,因为它允许每个数据库服务器服务更多的租户。然而,因为多个租户共享相同的数据库表,这种方法可能会导致安全问题,你必须努力确保租户始终不能访问其他租户的数据,即使在发生意外。
缺点:对于租客还原数据的过程是类似于共享架构方法,要重新插入临时数据库单个行到生产数据库中。如果有非常大量的受影响的表中的行,这可能导致性能明显降低数据库服务的所有住户。共享架构方法能够用少量的服务器,服务一大批租户和潜在客户,如果他们愿意用更低的费用获取安全性.
每次CRUD都需要使用对应租客 标识符ID.SQL变得复杂.

4.Multi-tenancy in Hibernate

使用Hibernate的多租户数据归结为一个API,然后集成块(无法表述了....)(Using Hibernate with multi-tenant data comes down to both an API and then integration piece(s))。
像往常一样,Hibernate努力保持API的简单.API只是通过打开任何会话的一部分定义租户标识符。

指定从SessionFactory指定租户标识符.

Session session = sessionFactory.withOptions().tenantIdentifier( yourTenantIdentifier )....openSession();

此外,当指定配置,一个org.hibernate.MultiTenancyStrategy应该被命名为使用hibernate.multiTenancy设置。 Hibernate会在指定的策略类型基础上执行验证。这里的策略是和上面讨论的隔离方法相关。

可以查看hibernate-core-4.2.0.Final的源码,在org.hibernate.MultiTenancyStrategy,可以查看此枚举量代码

package org.hibernate;import java.util.Map;import org.jboss.logging.Logger;import org.hibernate.cfg.Environment;
import org.hibernate.internal.CoreMessageLogger;/*** Describes the methods for multi-tenancy understood by Hibernate.** @author Steve Ebersole*/
public enum MultiTenancyStrategy {/*** Multi-tenancy implemented by use of discriminator columns.*/DISCRIMINATOR,/*** Multi-tenancy implemented as separate schemas.*/SCHEMA,/*** Multi-tenancy implemented as separate databases.*/DATABASE,/*** No multi-tenancy*/NONE;private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class,MultiTenancyStrategy.class.getName());public boolean requiresMultiTenantConnectionProvider() {return this == DATABASE || this == SCHEMA;}public static MultiTenancyStrategy determineMultiTenancyStrategy(Map properties) {final Object strategy = properties.get( Environment.MULTI_TENANT );if ( strategy == null ) {return MultiTenancyStrategy.NONE;}if ( MultiTenancyStrategy.class.isInstance( strategy ) ) {return (MultiTenancyStrategy) strategy;}final String strategyName = strategy.toString();try {return MultiTenancyStrategy.valueOf( strategyName.toUpperCase() );}catch ( RuntimeException e ) {LOG.warn( "Unknown multi tenancy strategy [ " +strategyName +" ], using MultiTenancyStrategy.NONE." );return MultiTenancyStrategy.NONE;}}
}

/**
  * 就是3.共享数据库,共享Schema(Shared Database, Shared Schema)
  */
 DISCRIMINATOR,
 /**
  * 2.共享数据库,彼此独立的Schema(Shared Database, Separate Schemas)
  */
 SCHEMA,
 /**
  * 1.分离数据库(Separate Databases)
  */
 DATABASE,
 /**
  * No multi-tenancy
  */
 NONE;

2. MultiTenant Connection Provider

When using either the DATABASE or SCHEMA approach,这个是the org.hibernate.service.jdbc.connections.spi.MultiTenantConnectionProvider contract的任务.应用程序开发人员将需要提供执行这个contract。可能不是唯一的getAnyConnection 和releaseAnyConnection.必须要注意的是,这些方法不接受租户标识符。 Hibernate使用这些方法在启动过程中执行各种配置,主要通过的java.sql.DatabaseMetaData对象.接口代码如下:

package org.hibernate.service.jdbc.connections.spi;import java.sql.Connection;
import java.sql.SQLException;import org.hibernate.service.Service;
import org.hibernate.service.spi.Wrapped;/*** @author Steve Ebersole*/
public interface MultiTenantConnectionProvider extends Service, Wrapped {/*** Allows access to the database metadata of the underlying database(s) in situations where we do not have a* tenant id (like startup processing, for example).** @return The database metadata.** @throws SQLException Indicates a problem opening a connection*/public Connection getAnyConnection() throws SQLException;/*** Release a connection obtained from {@link #getAnyConnection}** @param connection The JDBC connection to release** @throws SQLException Indicates a problem closing the connection*/public void releaseAnyConnection(Connection connection) throws SQLException;/*** Obtains a connection for Hibernate use according to the underlying strategy of this provider.** @param tenantIdentifier The identifier of the tenant for which to get a connection** @return The obtained JDBC connection** @throws SQLException Indicates a problem opening a connection* @throws org.hibernate.HibernateException Indicates a problem otherwise obtaining a connection.*/public Connection getConnection(String tenantIdentifier) throws SQLException;/*** Release a connection from Hibernate use.** @param connection The JDBC connection to release* @param tenantIdentifier The identifier of the tenant.** @throws SQLException Indicates a problem closing the connection* @throws org.hibernate.HibernateException Indicates a problem otherwise releasing a connection.*/public void releaseConnection(String tenantIdentifier, Connection connection) throws SQLException;/*** Does this connection provider support aggressive release of JDBC* connections and re-acquisition of those connections (if need be) later?* <p/>* This is used in conjunction with {@link org.hibernate.cfg.Environment#RELEASE_CONNECTIONS}* to aggressively release JDBC connections.  However, the configured ConnectionProvider* must support re-acquisition of the same underlying connection for that semantic to work.* <p/>* Typically, this is only true in managed environments where a container* tracks connections by transaction or thread.** Note that JTA semantic depends on the fact that the underlying connection provider does* support aggressive release.** @return {@code true} if aggressive releasing is supported; {@code false} otherwise.*/public boolean supportsAggressiveRelease();
}

这个MultiTenantConnectionProvider可以在许多方面指定使用:

  • 使用的hibernate.multi_tenant_connection_provider设置。它可以命名MultiTenantConnectionProvider实例,MultiTenantConnectionProvider的实现类引用或MultiTenantConnectionProvider实现类的名称。
  • 直接传递到org.hibernate.service.ServiceRegistryBuilder
  • 如果上面的选项中的不匹配,但设置指定一个hibernate.connection.datasource 值,hibernate将假定它应该使用的具体 org.hibernate.service.jdbc.connections.spi.DataSourceBasedMultiTenantConnectionProviderImpl 实现,工作很合理的假设的数目在应用程序服务器运行时和使用租客每一个 javax.sql.DataSource。请参阅其 javadocs 更多详细信息。

CurrentTenantIdentifierResolver

org.hibernate.context.spi.CurrentTenantIdentifierResolver是一个contract为了应用程序认为当前租户标识符Hibernate能够解决什么。要么是通过实现使用直接到配置通过其setCurrentTenantIdentifierResolver方法。它也可以被指定通过hibernate.tenant_identifier_resolver设置。

有2情况CurrentTenantIdentifierResolver用于:
第一种情况是,当应用程序使用的org.hibernate.context.spi.CurrentSessionContext与多租户功能。在当前会话功能的情况下,如果它不能找到一个现有的范围,Hibernate将需要打开一个会话。然而,在多租户环境中租户标识符被指定,当打开一个会话。CurrentTenantIdentifierResolver进场,在Session打开时Hibernate会咨询您提供给确定租户使用的标识符。在这种情况下,它是必需的提供一个CurrentTenantIdentifierResolver。

另一种情况是,当你不想明确指定租户标识符所有的时间,我们看到在例子中,“从SessionFactory指定租户标识符”。如果一个CurrentTenantIdentifierResolver已被指定,Hibernate会使用它来确定Session打开时默认的租户使用的标识符。
例子:Session session = sessionFactory.withOptions()
        .tenantIdentifier( yourTenantIdentifier )
        ...
        .openSession()

此外,如果的CurrentTenantIdentifierResolver实现返回true用于其validateExistingCurrentSessions方法的,Hibernate将确保任何现有的会话中发现的范围有一个匹配的租户标识符。此功能只使用CurrentTenantIdentifierResolver在当前会话设置相关。

Caching

多租户支持Hibernate能够无缝地使用Hibernate二级缓存。The key used to cache data encodes the tenant identifier.

零碎的事情

目前架构的出口不会真正多租户工作。这可能不会改变。

JPA专家组是在这个过程中做多租户支持,为即将到来的2.1版本的规范定义。

Strategies for MultiTenantConnectionProviderimplementors

Implementing MultiTenantConnectionProvider using different connection pools:

/*** Simplisitc implementation for illustration purposes supporting 2 hard coded providers (pools) and leveraging* the support class {@link org.hibernate.service.jdbc.connections.spi.AbstractMultiTenantConnectionProvider}*/
public class MultiTenantConnectionProviderImpl extends AbstractMultiTenantConnectionProvider {private final ConnectionProvider acmeProvider = ConnectionProviderUtils.buildConnectionProvider( "acme" );private final ConnectionProvider jbossProvider = ConnectionProviderUtils.buildConnectionProvider( "jboss" );@Overrideprotected ConnectionProvider getAnyConnectionProvider() {return acmeProvider;}@Overrideprotected ConnectionProvider selectConnectionProvider(String tenantIdentifier) {if ( "acme".equals( tenantIdentifier ) ) {return acmeProvider;}else if ( "jboss".equals( tenantIdentifier ) ) {return jbossProvider;}throw new HibernateException( "Unknown tenant identifier" );}
}

上面的方法是有效的数据库方法。它也是有效的模式方法提供了底层数据库允许命名模式,连接在连接URL。

Implementing MultiTenantConnectionProvider using single connection pool

/*** Simplisitc implementation for illustration purposes showing a single connection pool used to serve* multiple schemas using "connection altering".  Here we use the T-SQL specific USE command; Oracle* users might use the ALTER SESSION SET SCHEMA command; etc.*/
public class MultiTenantConnectionProviderImplimplements MultiTenantConnectionProvider, Stoppable {private final ConnectionProvider connectionProvider = ConnectionProviderUtils.buildConnectionProvider( "master" );@Overridepublic Connection getAnyConnection() throws SQLException {return connectionProvider.getConnection();}@Overridepublic void releaseAnyConnection(Connection connection) throws SQLException {connectionProvider.closeConnection( connection );}@Overridepublic Connection getConnection(String tenantIdentifier) throws SQLException {final Connection connection = getAnyConnection();try {connection.createStatement().execute( "USE " + tenanantIdentifier );}catch ( SQLException e ) {throw new HibernateException("Could not alter JDBC connection to specified schema [" +tenantIdentifier + "]",e);}return connection;}@Overridepublic void releaseConnection(String tenantIdentifier, Connection connection) throws SQLException {try {connection.createStatement().execute( "USE master" );}catch ( SQLException e ) {// on error, throw an exception to make sure the connection is not returned to the pool.// your requirements may differthrow new HibernateException("Could not alter JDBC connection to specified schema [" +tenantIdentifier + "]",e);}connectionProvider.closeConnection( connection );}...
}

This approach is only relevant to the SCHEMA approach

转载于:https://my.oschina.net/zhaoqian/blog/164604

多租户数据架构以及hibernate支持(Multi-TenantDataArchitecture)相关推荐

  1. 我们需要什么样的数据架构?

    作者 | Stephanie shen 编译 | 火火酱,责编丨Carol 出品 | AI科技大本营(ID:rgznai100) 在大数据和数据科学的新时代,对企业而言,一定要有与业务流程保持一致的中 ...

  2. 租户隔离怎么做MYSQL_基于JPA实现SaaS多租户模式的数据存储——共享数据库,隔离数据架构...

    SaaS是Software-as-a-Service(软件即服务)的简称,这边具体的解释不介绍.多租户的系统可以应用这种模式的思想,将思想融入到系统的设计之中. 现在SaaS Multi-Tenant ...

  3. 多租户实现之基于Mybatis、Mycat的共享数据库,共享数据架构

    阅读文本大概需要3分钟. 前言 SaaS模式是什么? 传统的软件模式是在开发出软件产品后,需要去客户现场进行实施,通常部署在局域网,这样开发.部署及维护的成本都是比较高的. 现在随着云服务技术的蓬勃发 ...

  4. SaaS 系统架构,租户数据隔离模式与租户信息解析方案!

    这段时候在准备从零开始做一套SaaS系统,之前的经验都是开发单数据库系统并没有接触过SaaS系统,所以接到这个任务的时候也有也些头疼,不过办法部比困难多,难得的机会. 在网上找了很多关于SaaS的资料 ...

  5. 推荐一篇关于多租户Multi-Tenant数据架构的文章

    2019独角兽企业重金招聘Python工程师标准>>> 做为SaaS的基本特征,多租户对系统的很多方面都产生了很多深远的影响.就数据层面的架构来说,基本上分成了多租户共享单一数据库. ...

  6. 大数据架构+Lamba+Kappa+Unifield

    大数据架构+Lamba+Kappa+Unifield 前端+主数据服务(MDS)+后端 Tomcat  HBase ElasticSearch Pig Oozie Node.js JQuery 数据分 ...

  7. 多租户数据中心该如何布线?

    Gartner的预测,到2025年,80%的公司都会把数据和工作负载从本地数据中心,向多租户数据中心(MTDC).托管和云端迁移,并逐渐关闭原有的传统数据中心. 今天,我们正处在完美的风暴中,我们需要 ...

  8. 数据交换平台_从零开始理解大数据架构之数据交换平台

    项目简介 Exchangis是一个轻量级的.高扩展性的数据交换平台,支持对结构化及无结构化的异构数据源之间的数据传输,在应用层上具有数据权限管控.节点服务高可用和多租户资源隔离等业务特性,而在数据层上 ...

  9. 多租户saas 架构_[译/注] Force.com 多租户互联网应用开发平台的设计

    原文地址  http://cloud.pubs.dbs.uni-leipzig.de/sites/cloud.pubs.dbs.uni-leipzig.de/files/p889-weissman-1 ...

  10. 数据湖 VS 数据仓库之争?阿里提出大数据架构新概念:湖仓一体

    作者 |关涛.李睿博.孙莉莉.张良模.贾扬清(from 阿里云智能计算平台) 黄波.金玉梅.于茜.刘子正(from 新浪微博机器学习研发部) 编者按 随着近几年数据湖概念的兴起,业界对于数据仓库和数据 ...

最新文章

  1. 图像金字塔与resize函数
  2. vue从入门到进阶:自定义指令directive,插件的封装以及混合mixins(七)
  3. mysql binlog空间维护
  4. 携程回应突发故障:「bug已修复」;罗永浩再嘲iPhone11浴霸相机;React 16.10.0发布|极客头条...
  5. jquery 全国 三联 地址选择
  6. 力扣-590. N 叉树的后序遍历
  7. access做mysql前端,ASP+ACCESS留言板制作详细教程
  8. 数字调制系统工作原理_图文讲解液压系统溢流阀分类与工作原理
  9. 2022年最新版 | Flink经典线上问题小盘点
  10. 【机器学习|数学基础】Mathematics for Machine Learning系列之矩阵理论(18):方阵的幂级数
  11. JsonEquals - JSON 差异比较工具的使用
  12. 在公众号发文是怎么赚钱的
  13. README.md的内容格式
  14. 通过枚举法暴力破解6位数以内zip密码压缩包,使用pyzipper包:内嵌生成1-6位数字加密码所有组合函数
  15. 琼斯是计算体心立方弹性模量_《固体物理学》概念和习题 答案 ()
  16. Window提高效率的软件
  17. 如何使用 cri-docker 解决 Kubernetes 1.24 不支持 Docker 的问题
  18. 利用HTML和javaScript实现简单的加减乘除运算
  19. 随机输入日期计算星期几(1900年1月1日为基础)
  20. 51单片机上连YL69土壤湿度传感器获取的数据在LCD上显示出来

热门文章

  1. Environment.CommanLine返回的文件路径使用注意
  2. VS2010中的单元测试【转载】
  3. 如何搭建j2ee开发环境
  4. Android 耳机插入过程分析 (AudioManager部分)
  5. Box,( UVa, 1587 )
  6. 作业01-Java基本概念
  7. Selenium-鼠标操作
  8. P1019 单词接龙
  9. [项目回顾]基于Redis的在线用户列表解决方案
  10. (转)switch与ifelse的效率问题 .