当前位置: 首页 > news >正文

SaaS多租户系统架构设计

前言:多租户是SaaS(Software-as-a-Service)下的一个概念,意思为软件即服务,即通过网络提供软件服务。SaaS平台供应商将应用软件统一部署在自己的服务器上,客户可以根据工作的实际需求,通过互联网向厂商租用所需的应用软件服务,按定购的服务多少和时间长短向厂商支付费用,并通过互联网获得SaaS平台供应商提供的服务。SaaS服务尤其利于一些中小企业,以低成本实现自己的软件需求。


 一、SaaS多租户简介

1.1、SaaS多租户概念

多租户技术是一种软件架构技术,它是在探讨与实现如何于多用户的环境下共用相同的系统或程序组件,并且仍可确保各用户间数据的隔离性。它是为共用的数据中心内如何以单一系统架构与服务提供多数客户端相同甚至可定制化的服务,并且仍可保障客户的数据隔离。简单来说是一个单独的实例可以为多个组织服务。

1.2、SaaS多租户的优势

  • 开发和运维成本低

  • 按需付费,节约成本

  • 即租即用,软件版本更新快

  • 故障排查更及时

  • 大数据和AI的能力支持更强大

1.3、为什么要搭建多租户系统?

多租户是SaaS领域的特有产物,探究何为多租户需回归到对SaaS的理解上。

SaaS服务是指部署在云上的,客户可以按需购买,并通过网络请求就能获取到的服务;也就是说,在这样的场景下,会有N个客户同时使用同一套SaaS服务。

那么对SaaS服务供应商来说,构建SaaS体系需要完成两部分工作:上层服务+底层多租户系统。

上层服务是供应商对外售卖的软件服务,其可以为客户创造价值、为公司带来营收;而底层多租户系统则是SaaS模式实现的具体方式,公司在对外售卖SaaS服务时,需要考虑如何实现客户之间的数据隔离、服务的权限控制、计费管理等;因此需要引入多租户概念来解决上述问题。

通过多租户系统,公司可以更好的管理客户和上层服务,客户也可以更好的使用软件服务。这也就是多租户系统存在的意义了。

1.4、多租户模型

如图所示,涉及主要模型有以下几类:

(1)租户:指一个企业客户或是个人客户,租户之间数据与行为隔离,上下级租户间通过授权实现数据共享。每个租户只能操作归属或授权给该租户的数据;

(2)组织:如果租户是一个企业客户,通常就会拥有自己的组织架构;

(3)用户:租户下的具体使用者,拥有用户名、密码、邮箱等账号信息的自然人;

(4)角色:用户操作权限的集合;

(5)员工:组织内的某位员工;

(6)解决方案:为了解决客户的某类型业务问题,SaaS供应商一般都将产品和服务组合在一起,为客户提供整体的打包方案;

(7)产品能力:能够帮助客户实现场景解决方案闭环的能力;

(8)资源域:用来运行1个或多个产品应用的一套云资源环境;

(9)云资源:SaaS产品一般都部署在各种云平台上,例如阿里云、腾讯云、华为云等。对这些云平台提供的计算、存储、网络、容器等资源,抽象为云资源。


 二、SaaS多租户的数据隔离设计方案  

2.1、三种多租户数据隔离方案

多租户对于用户来说,最主要的一点就在于数据隔离。不能出现,我登了A用户单位的号,但是看到了B用户单位的数据。因此,多租户的数据库设计方案和代码实现就相当有必要考虑了。

目前开发者们普遍接受的SaaS多租户设计方案,常见的大概就3种:

即为每个租户提供独立的数据库、独立的表空间、按字段区分租户,每种方案都有其各自的适用情况。

  • 一个租户独立一个数据库

一个租户独立使用一个数据库,那就意味着我们的SaaS系统需要连接多个数据库,这种实现方案其实就和分库分表架构设计是一样的,好处就是数据隔离级别高、安全性好,毕竟一个租户单用一个数据库,但是物理硬件成本,维护成本也变高了。

  • 独立的表空间

这种方案的实现方式,就是所有租户共用一个数据库系统,但是每个租户在数据库系统中拥有一个独立的表空间。

  • 按租户id字段隔离租户

这种方案是多租户方案中最简单的数据隔离方法,即在每张表中都添加一个用于区分租户的字段(如tenant_id或org_id啥的)来标识每条数据属于哪个租户,当进行查询的时候每条语句都要添加该字段作为过滤条件,其特点是所有租户的数据全都存放在同一个表中,数据的隔离性是最低的,完全是通过字段来区分的,很容易把数据搞串或者误操作。

2.2、三种数据隔离架构设计的对比如下:

隔离方案成本支持租户数量优点缺点
独立数据库系统数据隔离级别高,安全性,可以针对单个租户开发个性化需求数据库独立安装,物理成本和维护成本都比较高
独立的表空间较多提供了一定程度的逻辑数据隔离,一个数据库系统可支持多个租户数据库管理比较困难,表繁多,同时数据修复稍复杂
按租户id字段区分维护和购置成本最低,每个数据库能够支持的租户数量最多隔离级别最低,安全性也最低

大部分公司都是采用第三种多租户设计方案:按租户id字段隔离租户 架构设计实现多租户数据隔离的。

2.3、MyBatis-Plus多租户插件优雅实现数据隔离​

该系统只有一个数据库,所有租户共用数据表。在每一个数据表中增加一列租户ID,用以区分租户的数据。增删查改时,一定要带上租户ID,否则就会操作到其他租户的数据。因此,这里的设计一定要重点考虑。

  我们要保证的就是一定不要忘记带上租户ID。一个很好的方案就是通过AOP的方案,隐式的为我们的每一个SQL带上这个租户ID。我个人是更喜欢使用MyBatisPlus来操作数据库的。它提供了插件的机制,我们可以通过拦截它提供的四大组件的某些对象,某些方法,来操作SQL,动态的为我们的SQL拼接上租户ID字段。

  当然,MyBatis-Plus高版本提供了更加方便的拦截器,并且已经将多租户插件放入JAR包,我们只需稍加实现,并将该插件加入到MyBatis的拦截器链中,就可以不用再显式的拼接租户ID字段了,降低了出错的概率。

篇幅有限,如果有兴趣查看我写的这篇文章:MyBatisPlus实现多租户功能


参考链接:

数云融合丨 一文让你弄懂多租户数据库设计⽅案

SaaS架构:多租户系统架构设计

SaaS模式下,多租户系统数据隔离实现方案

谈谈对多租户SaaS系统的简要理解 - 知乎

相关文章:

SaaS多租户系统架构设计

前言:多租户是SaaS(Software-as-a-Service)下的一个概念,意思为软件即服务,即通过网络提供软件服务。SaaS平台供应商将应用软件统一部署在自己的服务器上,客户可以根据工作的实际需求,通过互联网…...

Java自定义捕获异常

需求分析 ElectricalCustomerVO electricalCustomerVO new ElectricalCustomerVO(); electricalCustomerVO.setElcNumber(chatRecordsLog.getDeviceNumber()); List<ElectricalCustomerVO> electricalCustomerlist electricalCustomerMapper.selectElectricalCustomer…...

力扣--数组类题目27. 移除元素

给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 示例 1&#xff1a; 输入&#xff1a;nums [3,2,2,3], val 3 输出&#xff1a;2, nums [2,2] 解释&#xff1a;函数应该返回新的长度 2, 并且 n…...

实际并行workers数量不等于postgresql.conf中设置的max_parallel_workers_per_gather数量

1 前言 本文件的源码来自PostgreSQL 14.5&#xff0c;其它版本略有不同 PostgreSQL的并行workers是由compute_parallel_worker函数决定的&#xff0c;compute_parallel_worker是估算扫描所需的并行工作线程数&#xff0c;并不是您在postgresql.conf中设置的max_parallel_work…...

java定位问题工具

一、使用 JDK 自带工具查看 JVM 情况 在我的机器上运行 ls 命令&#xff0c;可以看到 JDK 8 提供了非常多的工具或程序&#xff1a; 接下来&#xff0c;我会与你介绍些常用的监控工具。你也可以先通过下面这张图了解下各种工具的基本作用&#xff1a; 为了测试这些工具&#x…...

【Java】基础入门 (十六)--- 异常

1.异常 1.1 异常概述 异常是指程序在运行过程中出现的非正常的情况&#xff0c;如用户输入错误、除数为零、文件不存在、数组下标越界等。由于异常情况再程序运行过程中是难以避免的&#xff0c;一个良好的应用程序除了满足基本功能要求外&#xff0c;还应具备预见并处理可能发…...

[javaWeb]Socket网络编程

网络编程&#xff1a;写一个应用程序,让这个程序可以使用网络通信。这里就需要调用传输层提供的 api。 Socket套接字 传输层提供协议&#xff0c;主要是两个: UDP和TCP 提供了两套不同的 api&#xff0c;这api也叫做socket api。 UDP和 TCP 特点对比&#xff1a; UDP: 无连…...

<MySon car=“宝马“ :money=“money“></MySon>有没有冒号

为什么car"宝马"没有&#xff1a; 但是 :money"money"就有&#xff1a; <script setup> import {ref} from vue import MySon from /components/MySon.vueconst money ref(100) </script><template><h3>father</h3><My…...

netty(三):NIO——多线程优化

NIO多线程优化 使用Boss线程来处理accepct事件使用Worker线程来处理读写事件&#xff0c;可以创建多个worker线程 package com.review;import lombok.extern.slf4j.Slf4j;import java.io.IOException; import java.net.InetSocketAddress; import java.nio.channels.*; impor…...

Linux操作系统--linux概述

1.Linux概述 Linux&#xff0c;全称GNU/Linux&#xff0c;是一种免费使用和自由传播的类UNIX操作系统&#xff08;OS&#xff09;。简单的说就是一种操作系统。在日常中常见的操作系统有一下三种: 2.linux起源和背景 (1).linux的诞生 linux操作系统是由李纳斯托瓦兹&#xf…...

数组中出现次数超过一半的数字

⭐️ 题目描述 &#x1f31f; OJ链接&#xff1a;数组中出现次数超过一半的数字 思路&#xff1a; 采用投票计数的方式&#xff0c;我们可以把每个数字都看成一次投票并且计数&#xff0c;那么最后剩下来的就是数组中数字出现次数最多的那一个。比如 { 1,2,3,2,2,2,5,4,2 } &a…...

网络优化工程师,你真的了解吗?

一、5G网络优化工程师到底是什么&#xff1f; 5G&#xff0c;就是我们通常所说的第五代移动通信标准&#xff0c;属于目前最热门的新技术趋势。随着2019年5G技术进入正式的商用阶段&#xff0c;拥有广阔的发展前景&#xff0c;备受瞩目。“5G工程师”这个词是一个概念词&#x…...

git 的常用命令

git是一个版本管理器&#xff0c;是程序员必备工具之一&#xff0c;其主分为三个区&#xff1a; 工作区&#xff1a; 暂存区&#xff1a; 仓库&#xff1a; 通过保持软件版本&#xff0c;分支&#xff0c;合并&#xff0c;等多种版本操作&#xff0c;使软件能在自己想要的版本…...

linux如何拷贝文件,删除多余的一级目录,用*号代替所有文件

加上*&#xff0c;代表目录下的所有文件 mv /home/user/dir1/dir1/* /home/user/dir1/可以使用mv命令的通配符来去掉一层目录。 例如&#xff0c;假设有一个名为/home/user/dir1/dir2/file.txt的文件&#xff0c;要将它移动到/home/user/dir2/目录下并去掉dir1目录&#xff0…...

springboot使用properties

一、方式1&#xff1a; 1.1.配置类&#xff1a; package cn.zyq.stater.config;import cn.zyq.stater.bean.User4; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework…...

Android中获取手机SIM卡的各种信息

通过以下工具类方法可以获取到手机SIM的各种信息数据&#xff01;&#xff01;&#xff01; package com.utils; import android.telephony.TelephonyManager; import com.baidu.platform.comapi.map.E; import org.json.JSONArray; import org.json.JSONObject; import java.…...

matlab 根据索引提取点云

目录 一、语法二、说明三、名称-值对应参数1、输入参数2、输出参数四、代码示例五、结果展示六、参考链接一、语法 ptCloudOut = select(ptCloud,indices) ptCloudOut = select(ptCloud,row,column...

蓝芯、四川邦辰面试(部分)

蓝芯 HTTP请求经过MQ异步处理后&#xff0c;怎样返回结果呢&#xff1f;grpc比起spring cloud的优缺点&#xff1f; 四川邦辰 SkyWalking的埋点具体是怎么操作的&#xff1f;newBing: SkyWalking支持两种埋点方式&#xff1a;自动埋点和手动埋点。自动埋点是指通过SkyWalking…...

openCV实战-系列教程13:文档扫描OCR识别下(图像轮廓/模版匹配)项目实战、源码解读

&#x1f9e1;&#x1f49b;&#x1f49a;&#x1f499;&#x1f49c;OpenCV实战系列总目录 有任何问题欢迎在下面留言 本篇文章的代码运行界面均在Pycharm中进行 本篇文章配套的代码资源已经上传 上篇内容&#xff1a; openCV实战-系列教程11&#xff1a;文档扫描OCR识别上&am…...

SpringBootWeb案例 Part 4

3. 修改员工 需求&#xff1a;修改员工信息 在进行修改员工信息的时候&#xff0c;我们首先先要根据员工的ID查询员工的信息用于页面回显展示&#xff0c;然后用户修改员工数据之后&#xff0c;点击保存按钮&#xff0c;就可以将修改的数据提交到服务端&#xff0c;保存到数据…...

KubeSphere 容器平台高可用:环境搭建与可视化操作指南

Linux_k8s篇 欢迎来到Linux的世界&#xff0c;看笔记好好学多敲多打&#xff0c;每个人都是大神&#xff01; 题目&#xff1a;KubeSphere 容器平台高可用&#xff1a;环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义&#xff08;Task Definition&…...

React hook之useRef

React useRef 详解 useRef 是 React 提供的一个 Hook&#xff0c;用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途&#xff0c;下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

网络编程(UDP编程)

思维导图 UDP基础编程&#xff08;单播&#xff09; 1.流程图 服务器&#xff1a;短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...

蓝桥杯3498 01串的熵

问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798&#xff0c; 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合

在汽车智能化的汹涌浪潮中&#xff0c;车辆不再仅仅是传统的交通工具&#xff0c;而是逐步演变为高度智能的移动终端。这一转变的核心支撑&#xff0c;来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒&#xff08;T-Box&#xff09;方案&#xff1a;NXP S32K146 与…...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行

项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战&#xff0c;克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...

push [特殊字符] present

push &#x1f19a; present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中&#xff0c;push 和 present 是两种不同的视图控制器切换方式&#xff0c;它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...

华为OD机考-机房布局

import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...

深入理解Optional:处理空指针异常

1. 使用Optional处理可能为空的集合 在Java开发中&#xff0c;集合判空是一个常见但容易出错的场景。传统方式虽然可行&#xff0c;但存在一些潜在问题&#xff1a; // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...