多租户方案
背景
在当下云计算时代,多租户技术在共用的数据中心以单一系统架构与服务提供多数客户端相同甚至可定制化的服务,并且仍可以保障客户的数据隔离。
核心述求:
- 资源复用
- 服务(数据)隔离
现状
- kinglink物联网平台 需要KOCA提供基于多业务系统的管理、登录、以及菜单权限的实现
- 现KOCA开发门户需要通过”项目“维度进行数据权限控制
- 现有的KOCA业务组件(人员、权限、系统参数)等不支持多租
- 各业务产品单位有不同的多租方案需求,(金证前海融资租赁平台Saas、智慧城市Paas)
目的
-
梳理多租户方案
-
选择KOCA对多租户的支持方案
-
评估KOCA多租户改造方案的影响范围
多租户概念
-
租户:在SaaS中一般指 企业用户、客户; 在PaaS 中一般指业务系统。租户是一个逻辑概念,可以理解为系统中使用资源的集合.
-
多租户技术(multi-tenancy technology): 或称多重租赁技术,是一种软件架构技术,它是在探讨与实现如何于多用户的环境下共用相同的系统或程序组件,并且仍可确保各用户间数据的隔离性
多租户模型
- 不共享任何资源
- 共享硬件资源
- 共享操作系统
- 共享数据库 : 各租户应用服务器使用共享数据库
- 共享容器(应用实例):各租户独享数据库,应用容器本身可以智能化的区分来自各个租户的请求
- 全共享: 所有资源共享,只开发一套程序,部署一次,便可满足所有租户对公共应用的需要
- 定制化多租户:部分应用全共享,部分应用共享容器或者数据库
几种场景
针对上述的多租户模型,这里只讨论两个数据和应用/平台层面的多租户场景
独立应用独立数据库
共享应用独立数据库
CatalogDB存储公共服务(人员、菜单、权限等)数据.
TenantDB存储业务服务数据.
数据隔离方案
多租户在数据存储上存在三种主要的方案,分别是:
- 行级别: 在每个数据库表里添加tenant_id字段,然后在每个查询语句也添加相应的tenant_id
- schema 级别: 每个租户有在同一个数据库内自己独立命名空间。补充:不同数据库中schema支持方式不一样,oracle只能通过创建用户创建schema, 用户与schema一一对应
- 数据库级别:每个租户创建独立的数据库。
下面是比较这几种实现方式的优缺点:
行级别 | schema级别 | db级别 | |
---|---|---|---|
租户创建时间 | 新增一条记录 | 慢 (需要创建schema和表 ) | 非常慢 + 可能需要运维支持 |
租户间泄漏数据风险 |
忘记添加 WHERE
|
比较安全 | 非常安全 |
侵入性 |
所有代码需要添加tenant_id 列条件 |
一般 | 非常少 |
不同租户间共享和合并数据 | 没任何问题 | sql可以跨数据查询 | sql无法实现,只能应用代码实现 |
数据库迁移 | O(1) | O(n) | O(n) |
其它成本 | 无 | 无 | 创建大量数据成本 |
额外运维成本 | 无 | 有可能,需要维护大量表 | 需要维护大量数据库 |
复杂度 |
到处添加tenant_id
|
利用PG特性 search_path
|
|
可行性 | 非常容易实现 | 确认是否是托管数据库。是否有权限 | 是否能按需创建数据库 |
切换租户成本 | 设置变量。tenant_id =? |
需要设置search_path
|
需要创建独立数据库连接 |
抽取独立租户数据 | 有点麻烦 | 容易 | 非常容易 |
补充:schema 和数据库(db)级别对于应用来说,在实现方式上可以统一
数据隔离实现方案
行级别隔离
行级别数据隔离,首先需要各表中包含类似tenant_id的字段(字段在各表中统一,方便处理)
-
业务代码sql实现
每个关联的业务CRUD都需要关联 tenant_id字段。
优点:完全可控
缺点:过于繁琐, 对已有业务sql的改造量较大,且容易遗漏
-
基于mybatis 拦截器实现 (mybatisplus TenantSqlParser可以参考)
框架解析原sql, 生成带租户ID的sql后执行。
优点:交由框架处理,绝大部分的业务CRUD的sql都不需要修改
缺点:部分复杂sql不支持
schema级别/数据库级别隔离
该级别的数据隔离,业务表都不需要包含类似tenant_id的字段
-
分库分表框架
利用分库分表框架进行数据隔离,将租户ID作为拆分规则,进行水平或者垂直拆分
- sharding-jdbc: jar
- TDDL: jar Taobao
优点:支持跨库事务(在租户场景下不重要)
缺点:除标准sql外大部分sql不支持,不同数据库支持力度不一致,如mysql兼容性好,oracle兼容性差
-
分布式数据库和中间件
利用分布式数据库如tdsql 进行数据隔离
- TDSQL
- MyCat中间件: 额外部署,在应用 - mycat - 数据库
-
多数据源切换(KOCA已支持, 推荐)
可以基于切面,在数据持久化之前,获取当前租户与数据源对应关系,使用DataSourceUtils.set(“db1”)
切换数据源
优点:不需要考虑sql的兼容性问题
缺点:系统的稳定性取决于切面选择是否合理,不当的实现容易出现数据串库的现象;异步线程不支持切换数据源
模式选择考量因素
上述几种数据隔离选择,主要从以下几个方面考量:
-
成本角度因素
设计和实现成本、运营成本。一般设计和实现成本(初始成本)越高,共享性越高,运营成本越低; 反之亦然。
-
安全因素
考虑业务和客户的安全方面的要求。安全性要求越高,越要倾向于隔离
-
租户数据(Saas)
系统要支持的租户数量。租户越多,越倾向于共享
平均每个租户存储数据占用空间。存储的数据越多,越倾向于隔离
每个租户的用户并发量。并发量越高,越倾向于隔离
是否为每个租户提供附加服务。提供的附加服务越多,越倾向于隔离
-
技术能力(不重要)
共享性越高,对技术的要求越高
KOCA平台多租户支持
KOCA多租户示意图
多租户相关功能点:
- 租户管理:CRUD. 不会直接面向应用的端用户,面向的是应用的运维。
- 租户数据隔离:从请求开始就应该能够区分这个请求是来自于哪个租户,请求处理时在调用链路上也须要带上租户上下文。数据的存取是依照租户隔离的。调用平台提供的服务时也是租户隔离的
租户管理实现
租户管理(CRUD)开发实现较为简单,但对于不同业务系统,租户代表的业务含义差异较大。KOCA平台提供以下支持方式:
- 各业务系统平台自行开发,KOCA平台不提供具体实现,但提供demo
- KOCA提供一种默认租户管理(如:子系统管理)实现,且租户和人员关联是解耦的(不能基于sql进行关联)
请求区分租户
登录认证
- 登录时携带租户ID,如登录时选择系统登录,适合用户和租户多对多场景
- 登录时不携带租户信息,登录认证成功后,返回的认证信息中包含租户ID, 适合用户和租户多对一场景
请求校验
登录成功后,访问系统请求时,携带认证信息,认证信息中包含租户信息
对业务数据的CRUD
基于租户ID的CRUD
-
行隔离:基于mybatis 拦截器实现 (已实现)
该实现由框架提供,主要支持对外提供扩展租户ID的接口 TenantIdProvider ,获取租户ID(”aaa“) 支持配置需要支持租户的表名、租户ID字段(tenant_id)
-
schema/数据源隔离:基于数据源切换实现(已支持,暂不需要调整)
公共服务的模块
功能点 | 表名 | 完成时间 | 所属组件 |
---|---|---|---|
字典 | koca_sys_dictionary | 2.5.0 | admin-basic |
菜单 | koca_sys_menu | 2.5.0 | admin-basic |
系统参数 | koca_sys_parameter | 2.5.0 | admin-basic |
流程管理 | ACT_xx_xx kwk_xx | 已支持 | admin-workflow |
自定义报表 |
业务关注点
-
有些业务表主键是用户手动录入的,譬如不同租户同时拥有 菜单 10001,
-
租户ID是否可以为空
总结
- KOCA设计尽量满足多种多租户场景(Saas, Paas)
- KOCA多租实现方案应满足几种数据隔离要求
- KOCA多租改动点需向下兼容,不对现有业务实现CRUD做大范围调整