我有一个困难的数据库设计决策,为我的客户基于网络的CRM的越来越多的分支机构提供多租户,我积极维护.
我很早就决定为每个分支使用单独的应用程序和单独的数据库,因为这是满足不同数据和代码要求的三个不同分支的最简单方法.我还想避免在每个查询中管理租户ID ,就像我在2007年建立的遗留经典ASP(cringe)应用程序一样......恐怖.
但现在分支机构的数据需求正在趋同,随着业务的扩展,我需要能够快速推出新的分支机构并共享全球产品SKU.
由于所有分支的表和视图都相同,并且现在可以使用更好的ORM工具来管理多租户应用程序,我想知道为多个分支创建共享数据库是否更好.
不太可能有多达10个分支机构.现在有3个.
在这方面具有实际经验的开发人员,您在我的情况下会做些什么?将应用程序和数据库分开,还是组合成一个巨大的系统?
编辑:伟大的微软的文章在多租户亲的利弊.我应该注意,分支之间的数据隔离不是主要问题.
sql-server asp.net database-design fluent-nhibernate multi-tenant
在过去的几年里,我开发了一个非常定制的PHP/MySQL应用程序,用于许多客户端.到目前为止,我一直在为每个客户创建一个新数据库和新安装.
这里的第一个明显问题是保持多个安装与任何代码更改保持同步; 第二个问题是每个安装都有大量用户; 对大多数客户而言; 其中一些用户是相同的 - 他们必须要记住许多单独的用户帐户和网址.
我现在正在将申请移至Laravel 5,并研究多租户的最佳实施方案; 所以寻求关于最佳实施的一点建议.我之前使用过Laravel,但绝不是专家.
就设置而言,这就是我的想法.
1个主数据库,用于保存表:
然后是每个安装的单独数据库,其中包含该安装所需的所有信息以及提交给该安装的所有信息.
理想的设置是用户可以转到子域,即installationname.appname.com; 使用他们的主登录详细信息登录并自动进入所需的安装; 或者转到appname.com,登录,然后选择要连接的安装.
我的问题是:
我确信有很多我没有想过的问题; 但是,如果有人有任何链接或指导,可能有助于这将是伟大的.第一次询问关于SO的问题,但过去在这里找到了大量的研究帮助,感谢社区!
更新 - 所以我想我现在有办法让这项工作; 使用上述单独的数据库; 组
protected $connection = 'tenant_connection'
Run Code Online (Sandbox Code Playgroud)
在与租户特定的数据库内容相关的模型中.
然后在头文件中的某个位置根据已在login/by subdomain上设置的会话变量设置所需的tenant_connection.
$tenant = Installation::where('installation', '=', $session['installation'])->first();
Config::set('database.connections.tenant_connection', array('driver' => 'mysql', 'host' => $tenant->db_hostname, 'username' => $tenant->db_username)... etc.
Run Code Online (Sandbox Code Playgroud)
假设关系可以跨越连接; 我不明白为什么这不起作用; 只需要找出最佳位置来设置租户连接.
我有一个" 多租户 " Flask Web应用程序,它与1个"主"MySQL数据库(用于查找客户端信息)和数十个"客户端"MySQL数据库(都具有相同的模式)连接.
我目前正在尝试使用SQLAlchemy和Flask-SQLAlchemy扩展来与数据库连接,但我很难找到一种方法来允许我在我的应用中定义的模型动态地将上下文从一个客户端数据库切换到另一个客户端数据库,取决于客户.
在Flask-SQLAlchemy站点上,一个简单的示例如下所示:
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://username:password@Y.Y.Y.Y/db1'
db = SQLAlchemy(app)
class User(db.Model):
# Etc.
Run Code Online (Sandbox Code Playgroud)
唯一的问题是,SQLALCHEMY_DATABASE_URI
配置是静态完成的.我可能需要在mysql://username:password@Y.Y.Y.Y/db1
和mysql://username:password@Z.Z.Z.Z/db1
(或任何其他任意MySQL URI)之间切换,具体取决于发出请求的客户端.
我发现了一些类似的问题(见下文),但是在使用Flask-SQLAlchemy扩展时,我还没有找到一种干净的方法.
使用sqlalchemy如何基于每个请求动态绑定到数据库引擎
我还看到了一些为处理分片数据库而提供的示例(也应该适用,因为数据库本质上是由客户端逻辑分片),但同样,Flask-SQLAlchemy没有特定的内容.
如果它有意义,我也可以直接使用SQLAlchemy,而不使用Flask-SQLAlchemy扩展.我是SQLAlchemy的新手 - 非常感谢任何帮助!
编辑:能够反映数据库中的表模式将是一个奖励.
我正在尝试构建基于Web的SaaS解决方案,并且我遇到了一条我不确定使用多租户或多实例的道路.我将尝试描述我想要实现的目标,以及每种方法的优点和缺点(我的观点,根据我所读到的).请提供您的建议,以防我错过任何一种方法而不是另一种方法.
正如我所提到的,我正在尝试构建的应用程序是一个SaaS解决方案,公司可以在其中创建帐户,每个帐户/公司都拥有自己的用户,客户,产品,服务等.每个用户; 谁是公司员工; 与一个帐户/公司相关的只能访问他/她公司的客户,产品和服务.公司可以拥有无限数量的客户,产品和服务,因此每家公司都应拥有自己的数据中心.
为此我决定创建一个共享数据库(为登录目的保存所有用户凭据)和多个数据库共享模式(每个帐户/公司的数据库).基本上,多租户.
然后有人建议使用Multi Instance,其中每个公司都有自己的应用程序实例(即代码,库,数据库,框架等)与其他公司完全分开.这听起来更好,因为我不需要处理额外的层,我需要确保每个租户的用户只能访问他们公司的数据.我认为值得一提的是我依赖Docker来实现这种方法(我之前从未使用过它),但我认为它缺乏功能(后面会更多)我将来需要(至少我没有通过一点点搜索找到它们.
但是,每种方法都有利有弊,所以我无法决定采用哪种方法.这是一个列表,但由于我缺乏对它们的了解,所以我可能会遇到一些我不知道的事情,或者是我在网上找不到的问题的解决方案:[每种方法都有一个有序列表,我跟着一个一个比较]
多租户:
多实例:
如果我想手动执行任何操作(因为手动为每个租户创建实例),所有优点和缺点都是多余的,这就是我怀疑Docker解决方案的原因,除非有办法解决这个问题,这可能是主要的问题的原因.如果您能够通过参考解决方案来回答问题,我将不胜感激,为什么您认为这种方法比其他方法更好.
我有一个现有的Java EE 6应用程序(部署在Glassfish v 3.1中),并且希望支持多个租户.我目前在我的应用程序中使用的技术/ API是
据我所知,添加多租户支持仅影响持久层.我的问题:以前有人这样做过吗?转换应用程序的步骤是什么?这会影响除持久性以外的其他层吗?
因此,将有大量租户,所有数据将驻留在相同的数据库架构中.
对于多租户单个共享数据库,tenantid字段是否应包含在主键和聚簇索引中?或者在tenantid上添加额外的索引,就像表现一样?
我们在生产系统上遇到性能问题,其唯一索引是主键上的聚簇索引.
所有sql select语句都在其linq到实体语句中以tenantid开头,例如
invoiceitems.tenantid = thecurrenttenantid order by invoicedate
Run Code Online (Sandbox Code Playgroud)
租户(tenantid uniqueidentifier主键,tenantname)外键(tenantid)索引(在tenantid上聚集)
客户(tenantid uniqueidentifier,customerid uniqueidentifier主键,customername varchar(50))外键(tenantid,customerid)索引(聚集在customerid上)
发票(tenantid uniqueidentifier,invoiceid uniqueidentifier主键,billcustomerid uniqueidentifier,shipcustomerid uniqueidentifier,invoicedate datetime)外键(tenantid,billcustomerid,shipcustomerid)索引(聚集在invoiceid上)
InvoiceItems(tenantid uniqueidentifier,invoiceitemid uniqueidentifier primarykey,invoiceid uniqueidentifier,lineitemorder int)外键(tenantid,invoiceid)索引(聚集在invoiceitemid上)
SqlAzure要求每个表都有一个聚簇索引,因此它当前只在primarykeyid上,因为这是默认值.现在,这是每个表的唯一索引.整个系统中的表中有各种外键,并且没有索引外键表字段.
我们正在尝试解决一些性能问题,并且想知道什么是最好的聚簇索引以及是否有任何其他索引可能有用.我们希望我们不必更改现有的聚集索引,除非我们必须这样做,但我们愿意这样做.在SqlAzure AFAIK中,您不能简单地调整现有表中的聚簇索引 - 您必须创建具有所需聚簇索引的新表,并将旧表中的所有记录插入到新表中(并处理所有外键约束和其他表依赖项).
所有sql select语句都以linq到entity语句中的tenantid开头.
invoiceitems.tenantid = thecurrenttenantid order by invoicedate
Run Code Online (Sandbox Code Playgroud)
一些sql select语句只有一个顺序 - 有些在引入子表时有一些其他连接条件值
invoiceitems.tenantid = thecurrenttenantid and invoice.invoiceid = invoiceitems.invoiceid order by invoicedate
Run Code Online (Sandbox Code Playgroud)
以下是一些想法(除此之外我们对其他人开放) - 哪一个最好,为什么?
加快访问租户的记录
选项1 - 在tenantid上添加非聚集索引 …
indexing database-design azure multi-tenant azure-sql-database
在我的应用程序中,每个用户都有自己的数据库,用户注册后创建.连接和数据库数据(数据库名称,用户名,密码)保存在默认数据库的表中.
try{
DB::transaction(function() {
$website = new Website();
$website->user_id = Auth::get()->id;
$website->save();
$database_name = 'website_'.$website->id;
DB::statement(DB::raw('CREATE DATABASE ' . $database_name));
$websiteDatabase = new WebsiteDatabase();
$websiteDatabase->website_id = $website->id;
$websiteDatabase->database_name = $database_name;
$websiteDatabase->save();
});
} catch(\Exception $e) {
echo $e->getMessage();
}
Run Code Online (Sandbox Code Playgroud)
现在我想在新用户的数据库创建后运行一些迁移.
可能吗?
谢谢
我见过的关于Multitenant数据库模型的每个教程都告诉您将TenantID放在每个表中:
zoos
-------
id
zoo_name
tenant_id
animals
-------
id
zoo_id
animal_name
tenant_id
Run Code Online (Sandbox Code Playgroud)
但是,这对我来说似乎是多余的.为什么不将tenant_id
列添加到zoos
表中并利用zoos
和之间的外键关系animals
?
你是否tenant_id
只是为了防止连接过于疯狂而添加到每个表中?它是防范错误的安全措施吗?性能考虑?
我正在评估MS云Windows Azure来托管3个完全分离的网站.
每个网站都有自己的数据库,它们没有连接,所以3个网站和3个数据库.
我的目标是优化启动项目的成本,并有可能按需扩大规模.
我想知道:
谢谢你的时间.
我当前的项目是在AWS中,将Cognito和微服务与Lambda结合使用。我们已经使用DDD设计了微服务,并且正在实现基本功能。
但是,业务需要API的用户能够被分类到为其工作的客户公司中,并且只能访问该客户公司的数据以及我们将拥有的任何基于角色的身份验证。
这不是一个完整的多租户解决方案,因为每个用户都将使用相同的网站,但是他们的帐户将与特定的客户端关联。
我所读到的有关在AWS中执行类似操作的所有内容都建议每个客户端使用一个用户角色或池,并在创建用户时将其与用户相关联,但是我们不希望这样做,因为客户端通常由2-3个用户组成,并且有很多客户。就用户池数量而言,这将很快变得难以维持。
我试图使用“常规”方式来思考解决此问题的方法,例如将域服务添加到体系结构中,该域服务专门设计用于通过调用用户微服务来将特定用户的客户端数据添加到每个请求,但这似乎过度复杂。我还考虑过更改体系结构以在每个微服务中包括基本用户和角色信息,但这似乎很麻烦。
我的问题是,是否有任何官方支持的方式以编程方式将数据添加到AWS Cognito配置文件中,并且以这种方式可以在创建账户后由客户端管理员通过前端网站进行更改?即使只是令牌中的clientId字段。
如果不是,那么遇到类似问题的任何人都会推荐什么作为用户池建议的替代方案。
谢谢。
编辑:
我也一直在调查几种方法可以做Cognito此配置文件使用属性,提到这里。似乎这是或多或少地实现我想要实现的目标的方法,但是我仍然希望听到有关替代方案或建议的信息。
authentication multi-tenant amazon-web-services microservices aws-cognito
multi-tenant ×10
asp.net ×2
azure ×2
laravel ×2
architecture ×1
aws-cognito ×1
docker ×1
flask ×1
indexing ×1
java ×1
java-ee ×1
java-ee-6 ×1
laravel-4 ×1
laravel-5 ×1
php ×1
python ×1
saas ×1
sql-server ×1
sqlalchemy ×1