这几年,在公司尝试转型做产品。所以引入了很多的产品的理念。不管是对产品的定义,还是针对产品的管理,以及摸索产品的落地等等。我之前更多的是接触的ToB端,所以想必也猜到了是一个SaaS模式的产品。其实,现在回想并总结,之前所做的产品并不理想。当然,在这里就不多的来介绍了。

在一个月前不久,我给了一个朋友一份代码,还包含对产品的技术框架以及规划的文档。补充说一下,我很庆幸在一个新的环境接手在重新设计产品。所以基于之前的沉淀,有了一定的提升。那么这个朋友也是我之前在一次技术交流会上分享技术的时候所认识的。这次呢,我们在微信上一起讨论关于SaaS模式的产品时,我给他灌输了我对部分产品的理解,以及我参与过的产品的一些经验,并给他一些思路和参考。

据悉,他现在也是在参与一个项目。大篇幅的概念过后,他显然有点不满足。加之我说我们现在所用到的一些技术方案时,他也变现得格外的感兴趣,并最后我也将一个产品的代码做了裁剪后,也一并分享给了他。

好了,写到这里,我觉得应该要进入主题了。

本篇文章呢,我想聊一聊关于SaaS产品里面一个重要的概念,多租户。这个也是他后来不断让我给他解释和讲解的内容,所以我索性整理一下。

在以往传统的项目中,我们一般地是面向特定的客户实现一套特定的系统,并部署到对应的企业内部中。不同的企业或组织各自部署一套自己的软件系统。而现在面向ToB端的SaaS模式,是将一套软件服务部署到云端或特定服务环境中,面向不同的企业或组织提供相同的服务。这也很符合目前“轻资产”的模式。这里有一张图比较形象:

多租户saas架构业务数据隔离 saas多租户设计_数据库


在SaaS模式的平台中,我们需要考虑和规划好如何将一套相同的服务提供给不同的企业或组织使用,并且有且只能使用或操作所属范围中的数据。当然,不同企业或组织对平台功能的使用,通常我们把这种使用的企业或组织客户称之为“租户”。所以,我们可以总结出一句话:多租户技术,是一种架构模式,是实现如何在多用户环境下共用相同的系统或程序组件,并且达到各用户间数据的“独立”的技术。

在SaaS平台里,注重的就是数据的“独立性”,也是隔离性。如何在共有的一套系统架构与服务,仍可以保障客户的数据相对独立的正常使用。这也是SaaS产品必须面对的问题。由此带来了一些新的挑战。

一般地,以支持多租户的运行技术总体可分为三种:独立数据库、共享数据库但独立Schema、共享数据库且共享数据表。他们各自又存在各自的优劣性。接下来,就具体聊一聊。

1、独立数据库

针对独立数据库的这种方式,首先需要业务层能够支持多数据源的配置,并且为每个租户创建或初始化一个数据库。应用程序和数据库都是独立的实例,因此它不会与任何其他独立实例交互。只为一个租户提供服务,拥有独立的服务、独立的数据库以及独立的请求处理。

多租户saas架构业务数据隔离 saas多租户设计_共享数据_02

优点:为不同的租户提供独立的数据库,有助于简化数据模型的扩展设计,满足不同租户的独特需求;如果出现故障,数据影响小、恢复数据比较简单。

缺点:增多了数据库的安装数量,随之带来维护成本和购置成本的增加这种方案与传统的一个客户、一套数据、一套部署类似,差别只在于软件统一部署在运营商那里。由此可见此方案用户数据隔离级别最高,安全性最好,但是成本较高。

2、共享数据库但独立Schema

共享数据库、独立Schema模式,是将多个或所有租户的数据放在一个数据库服务中,但是为每一个租户建立一个独立的schema。租户间数据彼此逻辑不可见,上层应用程序的实现和独立数据库一样简单。(补充:mysql数据中的schema比较特殊,并不是数据库的下一级,而是等同于数据库。)
优点:对于安全性要求较高的租户,是一种选择。提供了一定程度的逻辑数据隔离,但并不是完全隔离;每个数据库可支持更多的租户数量。
缺点:如果出现故障,数据恢复比较困难,因为恢复数据库将牵涉到其他租户的数据;如果需要跨租户统计数据,存在一定困难。这种方案是方案一的变种。只需要安装一份数据库服务,通过不同的Schema对不同租户的数据进行隔离。由于数据库服务是共享的,所以成本相对低廉。

3、共享数据库、共享数据表
共享数据库、共享数据表,指的是多个或所有租户共享同一个数据库(Database)。所有的租户数据都存在同一个数据和同一套表中。通过数据库或表设计的租户ID等租户标志字段,来表明该记录是属于哪个租户的。

多租户saas架构业务数据隔离 saas多租户设计_共享数据_03


优点:所有租户使用同一套数据库,所以成本低廉;能够简单进行数据聚合统计或分析。

缺点:隔离级别最低,安全性最低,需要在设计开发时加大对安全的开发量,数据备份和恢复最困难。

接下来,我聊一聊我们在某个产品上的实践。这里仅针对实现逻辑做简单梳理。不深入展开。

我们在开展某个ToB的SaaS产品规划时,采用的是微服务的模式。所以我们从路由网关、认证鉴权、以及对应的业务应用和数据库设计做了整体性的规划和实现。如下图,这是是我们之前设计的一版架构图,后来有所调整就不展开了。

多租户saas架构业务数据隔离 saas多租户设计_多租户saas架构业务数据隔离_04


在这个产品中,我们选择的是共享数据库、共享数据表的模式进行实践的。

首先,我们为了租户能否方便的访问,以及平台能自动识别访问是哪个租户,我们在接入层采用通过url来识别租户。即系统在初始化租户信息时,会随机生成一个租户编码(租户编码允许修改一次),用于saas平台的三级域名监听,通过在业务系统的处理和绑定,当接收到请求时,拦截器会自动识别对应的租户编码,并加载对应的租户信息。

其次,在业务处理时,租户标识编号作为必须条件带入,进行数据操作。这里可以拓展下。目前在构建时,我们预留了分库分表的处理策略。当我们的用户量和业务所残生的数据呈现线性增长模式时,采用一般性的单数据库或者读写分离已经远远不能满足访问性能的要求了。加上我们在很多微应用上采用的是一个数据库的原则。数据库的IO将是一个直接面临的问题。所以我们已经预留了按照租户分库的策略。

针对数据库分库,我推荐两个方案。一个是代码编程式的sharding-jdbc、一个是采用中间件技术(MyCat、DBLE)等。其中dble也是基于mycat的版本。

sharding-jdbc是代码编程的方式,通过定义对应的分库规则来引导对应的数据持久化到对应的库中。这种方式需要编码规范并且业务实现要关注这块逻辑。

数据库中间件,是将分库分表的规则逻辑从应用程序提取出来,在中间件上来维护对应的规则。好处就是降低了业务人员对数据处理的关注,让业务实现更关注业务实现。

在这里不具体展开对这些技术的详细讲解了。我们采用的是中间件MyCat1.6.5来实现。

接着,在MyCat中配置rule规则,通过tenantId%4的规则,将数据分到4个物理数据库中。在业务代码层,只需要指向一个数据库,通过数据库中间件来维持多数据源的连接和数据处理(如果涉及到分布式事务的话,请谨慎使用)。

最后,就是公约和规范了。其实,不管是采用编码式还是数据库中间件,我们都需要一个租户的唯一标识。然后建立数据库路由,以租户id为路由标识,来数据库语句路由到对应的数据库中去执行。在维护sql语句时,有一些需要注意或遵守的地方。

1、如果有全局表,那么在执行全局表数据时,可以按照对应的业务需求进行编写。
    2、如果需要执行某个租户的信息,那么Sql必须要加上租户的唯一标识条件,且放在第一位条件。
    3、如需要进行全局表或夸库数据联表查询,分开查询。具体的要结合中间件支持程度。
    4、数据库联表执行,尽量保持在3张表以内。超过3张表联表,可以拆分执行。