第三章 Net 5.0 快速开发框架 YC.Boilerplate-- 多租户介绍
在线文档:http://doc.yc-l.com/#/README
在线演示地址:http://yc.yc-l.com/#/login
源码github:https://github.com/linbin524/yc.boilerplate
源码gitee:https://gitee.com/linxuanming/yc.boilerplate
元磁之力框架技术群QQ:1060819005
视频教程:
- 元磁之力框架开源初心和框架设计介绍(上): https://www.bilibili.com/video/BV1VM4y1G7hC/
- 元磁之力框架开源初心和框架设计介绍(下): https://www.bilibili.com/video/BV15h411s7w6/
- 元磁之力框架数据库表和代码生成使用教程实战: https://www.bilibili.com/video/BV1oM4y137D5/
多租户设计
SaaS介绍
SaaS 是 Software-as-a-Service(软件即服务)的简称,随着互联网技术的发展和应用软件的成熟, 在 21 世纪开始兴起的一种完全创新的软件应用模式。它与“on-demand software”,the application service provider(ASP,应用服务提供商),hosted software(托管软件)所具有相似的含义。
它是一种通过 Internet 提供软件的模式,厂商将应用软件统一部署在自己的服务器上,客户可以根据自己实际需求,通过互联网向厂商定购所需的应用软件服务,按定购的服务多少和时间长短向厂商支付费用,并通过互联网获得厂商提供的服务。用户不用再购买软件,而改用向提供商租用基于 Web 的软件,来管理企业经营活动,且无需对软件进行维护,服务提供商会全权管理和维护软件,软件厂商在向客户提供互联网应用的同时,也提供软件的离线操作和本地数据存储,让用户随时随地都可以使用其定购的软件和服务。
对于许多小型企业来说,SaaS 是采用先进技术的最好途径,它消除了企业购买、构建和维护基础设施和应用程序的需要。
多租户介绍
多租户技术或称多重租赁技术,简称 SaaS,是一种软件架构技术,是实现如何在多用户环境下(此处的多用户一般是面向企业用户)共用相同的系统或程序组件,并且可确保各用户间数据的隔离性。
简单讲:在一台服务器上运行单个应用实例,它为多个租户(客户)提供服务。从定义中我们可以理解:多租户是一种架构,目的是为了让多用户环境下使用同一套程序,且保证用户间数据隔离。那么重点就很浅显易懂了,多租户的重点就是同一套程序下实现多用户数据的隔离。
本框架多租户设计方案
独立数据库(基于 Database 的方式)
这是第一种方案,即一个租户一个数据库,这种方案的用户数据隔离级别最高,安全性最好,但成本较高。
优点: 为不同的租户提供独立的数据库,有助于简化数据模型的扩展设计,满足不同租户的独特需求;如果出现故障,恢复数据比较简单。
缺点: 增多了数据库的安装数量,随之带来维护成本和购置成本的增加。 这种方案与传统的一个客户、一套数据、一套部署类似,差别只在于软件统一部署在运营商那里。如果面对的是银行、医院等需要非常高数据隔离级别的租户,可以选择这种模式,提高租用的定价。如果定价较低,产品走低价路线,这种方案一般对运营商来说是无法承受的。
作者设计意图:SaaS 模式平台化设计,从分库角度,可以有效的解决耦合度问题;在运维上考量,避免了牵一发而动全身的风险。
共享数据库,共享 Schema (基于 TenantId 的方式)
共享数据表,即租户共享同一个 Database、同一个 Schema,但在表中增加 TenantId 多租户的数据字段。这是共享程度最高、隔离级别最低的模式。 即每插入一条数据时都需要有一个客户的标识。这样才能在同一张表中区分出不同客户的数据。
优点: 两种方案比较,方案的维护和购置成本最低,允许每个数据库支持的租户数量最多。
缺点: 隔离级别最低,安全性最低,需要在设计开发时加大对安全的开发量; 数据备份和恢复最困难,需要逐表逐条备份和还原。
PS:该方案虽然在框架中预留了每个数据表对应 Entity 都有一个TenantId字段,但本框架目前采用 独立分库实现多租户,需要共享库的网友,可以在业务层自己区分。
多租户使用
框架定义了租户接口 ITenant
,并实现了默认租户逻辑:DefaultTenant
,使用者可以自定义实现租户逻辑,在相关的注入模块修改,
CustomAutofacModule.cs
注入模块进行相关配置。
//多租户注入
builder.RegisterType<DefaultTenant>().As<ITenant>().AsImplementedInterfaces().InstancePerLifetimeScope().PropertiesAutowired();