元数据驱动的 SaaS 架构与背后的技术思考

引言

作为业务系统技术开发同学,面向当下:

首先应该是快速搭建业务通路,让线上业务跑起来,快速试错,解决生存问题;

第二步是在链路畅通、业务基本跑起来的基础上,如何支撑业务跑得更快,就需要解决快速增长问题;

第三步,在完成支撑业务快速增长的基础上,要进行精细化提升,通过在支撑业务快跑间隙挤时间打磨系统功能和体验,踏踏实实花时间去抽象能力,沉淀产品,提升效能;

同时我们也必须面向未来,如何在抽象能力以及沉淀了产品的基础上,把所承载和沉淀的业务能力快速输出,贡献给整个行业,或为整个社会商业生态提供基座支撑。面向未来,将平台产品进行 SaaS 化升级,真正将能力进行有价值开放输出是我们提前要布局的核心方向。

将平台产品进行 SaaS 输出,需要解决那些问题呢?这里尝试把核心问题列举一下:

如何根据不同用户需求进行计算能力按需调度分配?(IaaS/PaaS)

如何满足用户数据安全性要求,严格隔离不同用户的数据,使用户只能看到自己的数据?(PaaS)

如何支持不同用户在标准的数据对象/数据模型上按需添加自定义的数据对象/扩展模型?(PaaS & SaaS)

如何按照不同用户进行按需功能搭配组合,满足不同用户从基础到专业级不同业务场景需求?(SaaS)

如何统一对平台产品进行升级而不影响用户已有数据及功能?(IaaS、PaaS、SaaS)

通过以上问题,我们可以看出,产品 SaaS 化输出的关键是如何对不同的用户通过标准+扩展能力按需进行算力、数据、安全、功能有效定制,支持多用户共性和个性的问题,即多租户的问题,同时也涉及到计费和服务水平等相关问题。我们下面来聊下上述问题的解题关键和解题思路:

第1个算力问题的核心是调度问题,弹性计算提供在 IaaS 层的统一算力调度能力,而 Serverless 则可以在 PaaS 层提供更高层次的算力调度能力。

第4个问题的核心是业务流程的抽象和业务功能的拆分。领域驱动设计以及服务化(微服务)在平台功能抽象拆分上提供了相对成熟的思路,催化了以纵向业务功能细分作为域划分的依据的服务化方案以及组织结构,主要诉求是在细分的业务功能服务基础上,能按需快速灵活的组合,从而支撑不同的业务模式,提供业务敏捷性,支撑业务创新求变。

当然反过来,由于纵向功能细分,业务功能域增多,整个业务链条上的咬合点越来越多,随之产生越来越多的数据来源冗余重复或者缺失,功能或者重合且各自发散,或者缺失,最终给整体业务带来较多数据远程桌面和功能的不一致性风险。这样一来,不仅横向端到端的业务串联成本高,而且关键路径的风险收敛成本比较高,矛盾冲突点集中在各纵向域功能和数据咬合处,具体表现为:

数据上:

无主数据,有数据需求无 owner;

大量重复且不一致数据;

功能上:

部分业务功能缺失;

域之间存在业务功能重复且行为不一致。

到底是纵向切分域还是横向分业务模式拉平来做,这个问题没有标准答案,更没有最佳答案。只有根据不同的业务发展阶段及时动态调整试错,换言之,这是一个不断寻找相对最优解的动态过程。

弹性计算和 Serverless 解决了算力的问题,领域驱动服务化设计解决了功能的拆分和按需搭配组合的问题,那么剩下的核心问题就是数据了:如何以一套统一的数据架构,既能支撑多租户的数据安全性需求以及通用的数据存储,也能支撑用户扩展的自定义数据对象定义和模型变更,同时也要保证数据定义层面的扩展和变更不会影响自身和其他租户业务功能的可用性。我们来分析下可能的方案(暂不考虑按服务边界进行数据库拆分):

统一的数据库,标准数据模型和扩展数据模型直接映射到物理表和索引:很显然,对于不同租户自定义的数据对象和数据模型要求是无法支撑的,物理数据模型会相互干扰、相互冲突直到无以为继。即使是对于所有租户完全标准的功能和数据存储,平台自身的标准模型升级的 DDL 也会对用户的可用性造成较大影响,所以显然是行不通的。

如果为每个租户创建各自的数据库呢?各自租户拥有各自的数据库,可以满足用户数据安全隔离的需求,也可以满足各租户自定义的数据需求,看上去像是一种合理的 SaaS 数据方案。但是仔细分析,会发现有两个明显的问题:

如果用户需要修改或者扩展现有物理数据模型而进行的 DDL 操作,必然会影响线上业务的整体可用性,也可能会影响到标准数据模型,从而影响到线上功能使用。

如果用户可自定义对物理模型进行扩展和定制,当平台进行模型升级的时候,极容易产生物理模型的冲突,导致新旧功能异常。

由于用户在各自数据库存在各自定义的扩展和定制,则平台数据模型和功能升级需要针对不同的租户进行分别验证,存在极大的升级验证工作量和风险。

以上两种方案可行性低,我们从其中发现的问题是:平台业务系统的逻辑模型到物理模型的直接映射是造成问题的主要因素。既然物理模型的变更是平台不稳定的动因,那么我们是否能通过解耦业务逻辑模型和物理模型的映射关系来尝试解决这个问题呢?

既然问题已经定义清楚了,如何解决这个问题呢?通常我们解决架构问题的一个“万能”的方法是:增加一个层次,我们也来套用一次,增加一个层次(元数据层)来解耦逻辑模型到物理模型强映射的问题。

首先,我们需要对业务进行建模,对业务进行抽象,定义出业务逻辑模型,然后对模型进行二次抽象,定义出逻辑模型的定义数据,实现业务模型的数据化,即模型的元数据(The Metadata of the Logic Model ),将模型结构存储为数据,而不是直接对应的物理存储结构。

其次根据定义出的元数据进行统一抽象,形成元数据逻辑模型。

将元数据逻辑模型映射到元数据物理模型,对应实际存储结构。

通过对业务模型的变更,形成对元数据层的数据变更,而不是物理结构的变更,从而实现业务逻辑模型同物理模型的解耦。

很多事情说起来好像挺简单,实际上是一个非常巨大的系统工程,将其付诸实践是挑战非常大的事情,而取得踏踏实实的成功则更难。上述问题的解题思路是 Salesforce 的解题思路,而且 Salesforce 不仅取得了成功,也接近将其做到了极致,下面我们站在巨人的肩膀上来看看 Salesforce 如何通过元数据驱动的架构(核心是基础数据架构)来支撑多租户的 SaaS 业务平台。
注意:由于 Salesforce 并未有对核心实现逻辑进行完全公开和说明,所以本文所整理的部分核心逻辑包含了作者的逻辑推理和解读,但是确实进行了逻辑验证和场景验证,如有纰漏和不全面的地方,欢迎讨论及指正。

元数据驱动的多租户架构

Salesforce 将 http://Force.com 定义为 PaaS 平台,http://Force.com 的基础就是元数据驱动的软件架构来支撑多租户应用。首先我来解释下什么是以元数据驱动的软件架构为核心。

一、多租户意味着什么

多租户的含义用一句话来描述就是:一个云平台,无数多个客户。

一个云平台的含义是:一个代码库,一个数据库,一整套共享的可扩展服务,包括数据服务、应用服务以及 Web 服务。

无数多个客户的含义是:每个客户都被分配一个唯一的租户 OrgID,所有的数据存储都是按照租户 OrgID 隔离的,所有的数据访问必须包含 OrgID,所有的操作也都是包含租户 OrgID 的,也就是所有的客户数据和行为都是被安全的通过唯一的租户 Org 进行严格隔离的。

每个租户/组织只能看到和定义按照自己租户 OrgID 隔离的自己版本的元数据和数据,而且只能执行自己租户 OrgID 所授权的行为,这样每个租户就拥有各自版本的 SaaS 方案。

二、元数据驱动意味着什么

元数据对于平台意味着平台数据的数据,对于租户意味着是关于租户数据的数据。

当用户定义一个新的用户表的时候,用户创建的不是数据库中的物理表,而是在系统态的元数据表中添加了一条记录,这个记录描述的是用户表的逻辑定义,是虚拟的,这个表并不在数据库中物理存在,而这条记录代表就是用户态的数据表。

当用户定义了用户表的一个新的字段时,用户并没有在物理表中创建物理字段,而是在系统态的元数据表中添加了一个记录,这个记录描述的用户表的字段组成的逻辑结构,是虚拟的,这个字段也不在数据库表结构中物理存在,而这条记录代表的就是用户态的用户表字段。

也就是通过存储在系统态的元数据表中的元数据记录作为虚拟用户的数据库结构。

三、元数据驱动的多租户整体架构

我们先来大概了解下元数据驱动的多租户的整体架构,整体架构大概分为 5 个逻辑层次:

底层数据架构分为三个层次:

最底层是数据层,存储了离散的系统和用户的业务数据,业务日常运营的数据存储在这里。

公共元数据层,存储了应用系统标准的对象和标准的字段定义,对底层数据的结构进行定义说明。

租户特定元数据,存储了租户自动的对象和自定义的字段定义,用于对底层的数据结构进行定义说明。

通用数据字典 UDD(Universal Data Dictionary) 运行引擎层实现了应用对象到底层数据存储的映射,包含对象模型操作、SOQL 语言解析、查询优化,全文搜索等功能,我们常说的 ORM 功能也是其核心功能,但比其复杂的多。

平台服务层提供 PaaS 层平台服务,提供应用对象模型的创建,权限模型创建,逻辑和工作流程创建以及用户界面的创建,包括屏幕布局、数据项、报表等。

标准应用层提供端到端的标准的业务应用功能。

租户虚拟应用层,用户可以在标准应用层或者平台服务层之上定义自己特有的业务应用功能,满足自己特定的业务场景需要。

你可能感兴趣的:(saas)