LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

SaaS多租户应用程序与数据库数据隔离方案设计与选择

admin
2025年1月25日 9:10 本文热度 471

     什么是SaaS    

软件即服务 (Software as a service,SaaS) 是一种通过互联网按需交付软件应用程序的方法,通常采用订阅方式。借助 SaaS,云服务提供商 (CSP) 可以托管和管理应用程序软件和底层基础设施,保证系统的可靠性。用户可以通过手机或电脑上的网络连接到应用程序。

通俗地讲,就是将用户的服务器相关硬件、操作系统、应用程序搬到云上,让软件提供商来维护。SaaS的优势多用于ToB的业务,将客户本地部署的系统迁移到云上,方方便客户的同时,软件提供商也创新了盈利模式。

SaaS对客户来说有什么优势呢?

  • 降低IT成本。减少硬件软件的投入、降低了维护成本、降低了人员成本。

  • 快速部署与更新。开箱即用,无需复杂流程。自动升级,及时发布和修复功能。

  • 高安全性。企业提供标准的安全防护能力、容灾恢复能力。

  • 弹性扩展。不担心硬件资源不足及系统访问瓶颈。

  • 随时随地访问。通过网络连接,实现多设备或异地办公。


  多租户数据隔离   

客户本地数据迁移到云上或者直接订阅使用云上产品,不可避免需要关注数据的安全隔离。使用单租户模式还是实现多租户数据共存与访问,企业在系统设计之初必须规划多租户的架构解决方案。

我们了解下租户概念:

  • 单租户: 每个数据库仅存储来自一个租户的数据,数据隔离性好。

  • 多租户: 每个数据库都存储来自多个独立租户的数据,数据隔离性相对差。

相信大家也有个疑问,在多租户场景中,为什么要进行用户数据隔离?操作数据时加条件筛选不也可以吗?如下查询:

SELECT * FROM orders WHERE tenant_id = '88888888';

如果开发者在某个地方漏掉 tenant_id 条件,可能出现以下问题:

  • 用户 A 能看到用户 B 的订单数据。

  • SQL注入可以绕过 tenant_id 条件访问其他租户数据。

通过数据隔离,上述问题就可以完全避免。尽管在操作数据时加条件在一定程度上可以实现多租户数据的隔离,但它存在明显的安全问题。在实际场景中,数据隔离通常是通过物理或逻辑上的手段综合实现的,具体包括分库分表、分区、租户标识符控制等方式。

多租户场景之所以要数据隔离,完全是出于数据安全与隐私保护。数据隔离可以降低数据泄露潜在风险、增强用户对企业系统的信任、符合隐私法规(如GDPR、CCPA等)。


   多租户架构方案   

多租户的架构中,最常见的方案主要有四种:

  1. 单租户模式,应用程序与数据库完全隔离。

  2. 单租户模式,应用程序共享系统资源,数据库完全隔离。

  3. 多租户模式,应用程序和数据库资源共享,数据库采用schema隔离。

  4. 多租户模式,应用程序和数据库资源共享,schema共享,数据采用行级隔离。

接下来,我简单介绍这几种方案的优劣情况和使用场景。

  • 单租户模式,应用程序与数据库完全隔离

优点:

  • 高隔离性:每个租户有独立的应用程序和数据库,安全性和隐私性最高。

  • 可定制性:针对不同租户可以自由定制应用程序和数据库配置。

  • 性能独立:一个租户的负载不会影响其他租户。

缺点:

  • 高成本:需要为每个租户提供单独的资源,资源利用率低。

  • 运维复杂度高:多个服务和实例带来的部署、更新和维护成本较高。

  • 扩展性差:当租户数量增加时,难以快速扩展。

场景:

  • 安全性要求极高的业务场景,如金融、医疗等。

  • 少量租户但需求差异较大的情况,如大客户的企业级服务。


  • 单租户模式,应用程序共享系统资源,数据库完全隔离

优点:

  • 高隔离性:每个租户使用独立的数据库,数据安全性强。

  • 资源利用率较高:应用程序层共享资源,相比上一个方案成本较低。

  • 性能独立:数据库的隔离性保证了不同租户之间的性能互不干扰。

缺点:

  • 中等运维复杂度:需要管理多个数据库实例。

  • 扩展成本较高:当租户数量增加时,仍需为每个租户配置数据库资源。

场景:

  • 中小型企业或中等数量租户的场景,不适合小微企业。

  • 数据隔离要求较高但对成本有一定限制的应用。


  • 多租户模式,应用程序和数据库资源共享,数据库采用 schema 隔离

优点:

  • 资源利用率高:应用程序和数据库实例共享资源,节约成本。

  • 管理相对简单:相比单租户模式,维护一个数据库实例而多个 schema 更加轻量化。

  • 隔离性中等:schema 提供了一定的逻辑隔离。

缺点:

  • 安全性较低:如果数据库的权限管理或隔离机制不足,可能导致数据泄露。

  • 性能隔离性有限:高负载的租户可能影响同一实例中的其他租户。

  • 复杂的权限管理:需要通过 schema 进行精细的权限划分。

场景:

  • 中小型 SaaS 产品,租户数量较多,但对数据隔离性和安全性要求适中。

  • 对成本敏感的企业级应用。


  • 多租户模式,应用程序和数据库资源共享,schema 共享,数据采用行级隔离

优点:

  • 成本最低:所有租户共享应用程序和数据库资源,资源利用率极高。

  • 管理最简单:统一的数据库架构,无需维护多个 schema。

  • 高扩展性:可以轻松增加租户数量,适合大规模扩展。

缺点:

  • 最低隔离性:租户间完全共享表结构,隔离性最低,容易受到数据泄露和误操作的风险。

  • 性能瓶颈:当租户数量或负载过高时,资源争抢可能导致性能下降。

  • 复杂的逻辑控制:需要在应用层实现租户级的行级权限管理,增加开发复杂度。

场景:

  • 对隔离性要求不高的大规模 SaaS 应用,如消费级互联网产品。

  • 对成本控制敏感,且需要支持海量小租户的场景。


  多租户数据库设计  

在设计有效的多租户数据库时,必须仔细平衡数据隔离、可扩展性、性能和安全性。对于成功运行的多租户系统,每一个要素都至关重要。随着租户数量的增加,数据库需要具有可扩展性,以便处理增加的负载。为了保证数据库能够快速有效地访问数据,性能至关重要。对于这些应用程序,需要考虑实时数据访问。

租户数据库的设计方案,需要结合自身的业务选型。在数据库方面,实现数据隔离主要有数据库、schema、行级这三种。当然也有分区模式和混合模式。

这三个方案会面临的问题,我简单总结如下:

通常SaaS场景下的单个租户数据量不会太大,一般从几十MB至几十GB。新方案初期难确定容量大小,当服务器性能无法满足时,再新增服务器分配新租户来使用。因此设计数据库的时候,需要一个专门存储租户信息的数据库,该数据库用于管理租户、同时也记录该租户数据所在的数据库连接信息。

如果明确租户增长不会太大,且业务功能的使用也不同(较多表可能存在数据倾斜),数据量都是几十GB的,推荐使用数据库隔离模式。我们可以将几十个数据库放在同一个实例中,有效利用计算资源。数据库隔离模式也适合schema隔离模式,当然需要考虑上面提到面临的问题。

当租户数量达成千上万的时候,或者未来租户数能达到这个量级,数据库隔离模式就不必再考虑了,schema隔离模式确实可以考虑。能使用schema模式的常见关系型数据库,如Oracle、SQL Server、PostgreSQL,但如果使用 PostgreSQL 的多schema隔离模式,autovacuum 可能会频繁执行,将是比较大的性能问题!

当上万的租户、或者数据量少的租户,推荐使用行级隔离。行级隔离的基本原理是,当用户操作数据库表时,系统判断是否是某个租户的数据,必须在连接会话中获取能识别租户的信息,如租户账号、租户ID等。获取到的信息需要与表中的行数据进行筛选匹配,如匹配表中字段tenant_id中的值,这样操作的数据只能是该连接的租户数据。

行级隔离不是简单地加where条件筛选指定的租户,因为无法不免有漏掉条件的可能。使用行级别安全(Row Level Security,RLS),即使不加租户相关条件,租户也只能操作自己的数据,达到租户之间的数据安全隔离。目前Oracle、SQL Server、PostgreSQL 等都支持行级别安全。

使用RLS也可能存在数据倾斜,导致数量差异大的租户操作SQL的执行计划不准确,该如何处理呢?前面提到过混合场景和分区方案就是其中的解决方案。数据库少的租户可使用RLS方案,数据量大的租户可以使用数据库或schema方案。另外还可以使用分区方案,分区方案只是辅助RLS解决数据倾斜问题,不作为正式的租户隔离方案。对于数据量大的租户,可以将表进行分区,一个或多个分区存储大租户的数据,另一个分区存储数据量少的租户。


 多租户实战案例  

我这里介绍两种案例:

  • SQL Server 使用视图进行“行级隔离”

  • PostgreSQL使用行级安全(RLS)功能进行隔离

  • SQL Server 使用视图进行行级隔离

SQL Server有真正的行级隔离方案,但这里我介绍的是另一种非正式的隔离方案,可以说也是一种通用方案,在其他数据库都可以实现。

该方案在视图中添加where条件,识别当前上下文环境的登录用户ID,到表中进行筛选。以下是一个完整的简单示例。

-- 创建测试表CREATE TABLE dbo.demo_tab(	id uniqueidentifier NOT NULL DEFAULT (newsequentialid()),	tenant_id varbinary(85) NOT NULL DEFAULT (suser_sid()),	order_id bigint NOT NULL,	CONSTRAINT pk_demo_tab PRIMARY KEY CLUSTERED (tenant_id ASC,id ASC))GO-- 创建视图CREATE VIEW dbo.v_demo_tabASSELECT * FROM dbo.demo_tab WHERE tenant_id = SUSER_SID()GO-- 插入5行数据(DML 只操作自己的数据)INSERT INTO dbo.demo_tab(order_id) select round(rand()*1000,0)GO 5
/*UPDATE dbo.v_demo_tab SET order_id = 1GODELETE FROM dbo.v_demo_tabGO*/SELECT * FROM dbo.v_demo_tab -- SELECT * FROM dbo.demo_tab
--添加字段后刷新视图ALTER TABLE dbo.demo_tab ADD order_name VARCHAR(10)GOEXEC sp_refreshview 'dbo.V_DemoTab';GO
-- 也可以切换为指定用户进行操作EXECUTE AS USER = 'huang';GOSELECT SUSER_SID(),SUSER_NAME()GO

应用程序只操作视图,每张视图背后都对应一张表。由于视图已经隔离了用户数据,任何用户都不可能操作其他用户的数据。如果表结构发生变化,可以通过存储过程sp_refreshview刷新视图定义。这是我以前公司用的一种租户隔离方案,类似RLS。当前你也可以使用SQL Server 官方真正的“行级别安全性(RLS)”设计租户隔离。

  • PostgreSQL使用行级隔离RLS

另一个实际的案例就是PostgreSQL的“行级安全策略(RLS)”。每张表都存在字段tenant_id,存储租户id,租户id的管理可以从平台数据库中获取。

# 创建容器环境docker run -d --name pg5401 -e POSTGRES_PASSWORD=123456 -p 5401:5432 postgres:latestapt install postgresql-client
# pg管理员登录创建测试数据库及用户psql -h 127.0.0.1 -p 5401 -U postgres -W -d postgrescreate database mydb with encoding = 'utf8';create user myrole password 'myrole' login;\c mydbgrant all privileges on all tables in schema public to myrole;grant all on schema public TO myrole;

# pg用户登录,创建对象及启用行级安全psql -h 127.0.0.1 -p 5401 -U myrole -W -d mydb
create table product(tenant_id varchar(50) not null,id int,name varchar(50));
insert into product values('10000',1,'10000'),('10001',2,'10001'),('10002',3,'10002'),('10003',4,'10003'),('10004',5,'10004'),('10000',6,'10000'),('10000',7,'10000'),('10002',8,'10002'),('10000',9,'10000'),('10004',10,'10004');
select * from product;
-- 针对表启用行级安全策略alter table product enable row level security;
-- 针对表创建策略drop policy if exists product_tenant_isolation_policy on product;create policy product_tenant_isolation_policy on product using(tenant_id = current_setting('app.tenant_id'));\d product
-- 强制所有用户使用 RLS,否则表 Owner 的用户会绕过行安全性alter table product force row level security;
-- 具有该属性的超级用户和角色 BYPASSRLS 在访问表时始终绕过行安全系统 (指定用户绕过 RLS,可访问全表数据)-- alter user my_admin with bypassrls;  
-- 重新连接操作psql -h 127.0.0.1 -p 5401 -U myrole -W -d mydbselect * from product;-- ERROR:  unrecognized configuration parameter "app.tenant_id"
set app.tenant_id = '10000';show app.tenant_id;-- reset app.tenant_id;
insert into product(tenant_id,id,name)values('10004',99,'kk');update product set name='kk';-delete from product;
# 或者直接命令行操作export PGPASSWORD='myrole'env PGOPTIONS="-c app.tenant_id=10000" psql -h 127.0.0.1 -p 5401 -U myrole -d mydb -c "select * from product;"

我们定义策略参数app.tenant_id,当租户连接数据库时,需要设置app.tenant_id的值。当访问表的时候,rls策略将获取上下文信息app.tenant_id的参数值,相当于将“tenant_id=?” 拼接到where条件中,与前面的“SQL Server 使用视图进行行级隔离”有相似之处。


   总结  

数据库级别与schema级别的数据隔离比较好理解,对租户来说隔离性好,但不适合大量租户的情况。一个企业的租户数据量差异比较大,这就需要考虑产品是否真的符合租户的业务场景。也就是说,企业内部需要对发布多个版本或多个产品满足不同的客户需求,在多租户的数据库设计方面也评估使用不同的数据隔离方案。

我们除了在数据库选型、租户架构选型之外,也要考虑云资源成本。客户获取成本、 客户生命周期价值、月度经常性收入、 客户流失率 是SaaS提供商特别关注的一些关键绩效和业务指标。这些指标对于业务优化和增长至关重要,并且它们提供了SaaS公司财务状况的全面概览。针对租户资源的成本占比、租户均值成本等,评估租户开销是否超出了计划。


阅读原文:https://mp.weixin.qq.com/s/Ba_KqWY5a_SAKN4RvPqH5Q


该文章在 2025/1/25 9:13:25 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2025 ClickSun All Rights Reserved