Categories
程式開發

从业务数据库到元数据,SaaS架构设计经验全总结


SaaS可以说是软件交付方式演化路径中必需的一环,它的存在有其社会意义与必然性,这是社会动力体系的经济属性中成本驱动力诱发的。SaaS也是算力与网络发展的必然,随着算力与网络带宽的极大提高,这个世界的计算样态可能都会改变,未来有些场景可能更趋于中央计算(核心算力都在云上,接入的设备不需要很强的算力,甚至仅为终端)。SaaS在中国正以其自有的节奏稳步发展中,笔者曾深度参与过三个SaaS项目的工作,本文力求从实用的角度分享一些关于SaaS架构的经验要点,所谓自见者不明、自是者不彰,希望能借此文与各位读者有进一步的交流。

未来社会模型中SaaS的位置与分量

从业务数据库到元数据,SaaS架构设计经验全总结 1

上图是一个从连接这个透视角度抽象出来的社会模型,其中的家庭、人、组织、物都是相互连接的,它也是一个从软件架构抽象出来的社会模型。SaaS是对软件的获得和使用方式的革命,早在2004年就已有端倪(当时称为ASP,Application Service Provider)。笔者认为,可以将SaaS放在社会运行机制、发展趋势这样的大格局中定位其社会作用。SaaS企业也需要这样的格局与信念,虽然在中国还没有出现非常成功的SaaS企业,但终究会出现的,信任、习惯、规范、与能力都需要进化,需要时间。

在没有电之前,人们就有传递信息的需求,这也是为什么微信能够存在的本质根由。同理,各种组织都离不开软件,而且软件的渗透越来越广泛与深入,因为整个世界的数字化是不可阻挡的趋势。而SaaS在大部分情况下是必选之路,会越来越成为标配,除非特殊原因,或者不在乎成本、或者已经拥有某种等效的软件、或者其他原因。只要这种本质性的需求存在着,社会的发展终究会以越来越先进的方式来满足它。

这里分享一个关于云的小故事,笔者曾经算过一笔账,如果在云上订购托管机房中约500台机器的同等算力,每年需要支出5000万,相当有悖于流行认知,其实对于稍微有些规模的IT资源诉求,云相对是更加昂贵的,但来的快、方便,两方面都是事实。

这里只想传递一个观点,长远来看,SaaS有它存在与发展的必然性。结构上讲,它是社会运行机制中不可或缺的一部分。同样或者类似的软件,显然没有必要每个人、每个组织都各买一套或各自开发一套,这是社会资源的极大浪费,有悖于社会发展的基本规律——既然是必需的,必然选择物美价廉。而且组织支出比个人支出更理性、更注重实用价值,有利可图的需求终究会达到稳态的、某种主流服务的满足。

从架构角度看SaaS面临的挑战

如果说SaaS在大部分情况下将会成为必选之路,那么它面临的最大挑战又是什么呢?概括来讲,SaaS面临的最大挑战是满足客户的个性化需求。从架构角度看,它体现在如下图所示的几个方面:

从业务数据库到元数据,SaaS架构设计经验全总结 2

其中最有挑战性的又要属多变的后台逻辑与数据模型。对于SaaS供应商而言,这种需求显然不能通过项目的方式来定制满足,而只有通过提供灵活的自服务平台才能满足,这种灵活性就需要用PaaS来生产客户想要的软件。这一点笔者在2013年做一个SaaS项目的架构工作时就深有体会:一开始的目标也是做SaaS,但是后来还是走上了PaaS的道路,不过是专为生产SaaS而自用的PaaS,而不是定位于PaaS供应商。

如果一个SaaS企业从一开始就只是聚焦某个业务,而没有着手PaaS的建设,那说明它在满足个性化需求的道路上一定是在某个局部、某个层面解决问题,而不是系统、全面、可复用地解决问题。同时,从中国SaaS市场现状来看,它的成长比较慢,环境的综合成熟度还不够高,聚焦单一业务成长的加速度不够,因此企业后续很可能会从最开始聚焦的核心业务向外扩展,到时候又要面临种种个性化需求问题。因此,一个成功的SaaS企业必然要去寻求PaaS的支撑。从这两个意义上讲,PaaS可能也是SaaS企业提高生产力的必经方向。据有关数据表明,在企业弃用SaaS的原因中,无法满足个性化需求占了23%,可见PaaS的支撑多么重要。

如何做好SaaS架构?

1 业务数据库

SaaS,特别是To B的时候,业务数据库必然是存储的核心,这里笔者针对业务数据库总结了一些架构层面的建议。

建议一:对于任何mission critical的场景都要使用RDBMS

企业应用与To C的使用场景有一个明显的区别是,绝大部分情况下,它对正确性、准确性的要求更高,而且SaaS提供方需要对此承担相应的责任。因此,支撑一线黄金业务流程的数据库目前来看还是得使用关系型数据库。目前来看有两个开源可选项,分别是MySQL和PostgreSQL。

建议二:分库

支持多租户可以有多种方式,这里所说的分库并不是指每个租户一个独立的库(当然产品销售时可以作为套餐的一个选项),而是指多个数据库实例,每个实例包含多个租户的完整数据。

说到多租户,需要提个醒,通常大家都会想当然地认为租户之间是隔离的,但是事情都有另一面,对于大集团客户,在某些业务上,它的分公司、子集团之间可能还是有连接的。另外,人员组织机构建模上,也要考虑一个人任职多个子集团或公司的可能。

建议三:Partitioning

即使是一个数据库实例,也可以再继续分区,MySQL和PostgreSQL(至少版本11以上)都支持在一个实例内部分区。对租户进行Partitioning可以在一定程度上提高性能,因为把一个查询限制在更小的数据范围内进行,而非全量数据空间,效率自然会更高。

建议四:元数据驱动,Salesforce不是标杆

一个民族、一个国家如果没有非权威精神,是不会有根本性创新的。动则大厂是如何做的,好像大厂总是做的最好的,那是不行的,盲目崇拜只能是follower,不可能是creator,当然也不能盲目忽视,最要紧的是把业务架构搞清楚、明确定义到底要什么。心里要有谱,但是技术本身绝对不是谱,而仅仅是可选的手段。

以下是根据Salesforce官网资料整理的的核心数据模型:

从业务数据库到元数据,SaaS架构设计经验全总结 3

其业务数据表本身是没有物理索引的,真正的索引主要在MT_Indexes中,但是这有点让人困惑,为什么不在MT_Data上直接建立物理索引呢?难道列和索引太多了会影响性能?而反范式地单独以列的方式、按数据类型建立很少的索引就好?为此,笔者动手做了验证。

1)实验条件

为了聚焦在问题本身,图 3中只采用了绿色的两张表,而省略了红色的字段,本实验所使用的字段名和图 3不一样,但是思路是一样的。

  • OS,Windows 10;

  • DB,MySQL 5.7;

  • 两张业务表,有物理索引的=bizdata,没有物理索引的=bizdata2,结构如下:

    从业务数据库到元数据,SaaS架构设计经验全总结 4

  • bizdata和bizdata2都灌入了10万条数据,字符型长度为4,它的值基于给定的一个长度为10的字符串随机生成,数值型的则为100以内的随机数;

  • 索引表为pivot_index,其中rowid的值等于业务表中id的值,col是列名,它们可能的值是c1-c5、n1-n5,string_value和int_value分别容纳的是字符型和数值型的业务数据值,总的数据行数是100万行。

    从业务数据库到元数据,SaaS架构设计经验全总结 5

2)实验结果

以下比较,除了SQL形态上不一样,从语义上讲,条件与期望的结果都是完全一样的。汇总如下:

# 方式 结果(秒)
1 MT_Data(自身无物理索引) + MT_Indexes,Salesforce方式 5.39
2 MT_Data(自身有物理索引) 0.05
3 MT_Data(自身无物理索引) 0.13
4 MT_Data(自身无物理索引),且字符字段都采用条件 like ‘%xxxx%’ 0.16

使用Salesforce索引表(相当于业务数据表MT_Data上没有物理索引,红框部分为行变列的pivot逻辑,其实红框外的条件在都是or的情况下是可以省略的,否则不可以,这里仅仅为了体现逻辑完整结构,Salesforce后台用的是Oracle,也许性能比MySQL好不少,也许Oracle有pivot的核武器,不过从逻辑上讲,就算给Oracle更大的想象空间,行数倍增也是不争的事实)的结果:

从业务数据库到元数据,SaaS架构设计经验全总结 6

直接使用物理索引(相当于业务数据表MT_Data上有物理索引)的结果:

从业务数据库到元数据,SaaS架构设计经验全总结 7

直接使用没有物理索引的业务数据表(相当于不考虑MT_Indexes)的结果:

从业务数据库到元数据,SaaS架构设计经验全总结 8

在没有使用物理索引的bizdata上用’%xxx%’,看情况如何:

从业务数据库到元数据,SaaS架构设计经验全总结 9

3)实验结论

结论是不要采用Salesforce的元数据使用方式,因为其行列转换的性能损失相当大。此例相当于把数据行数放大了10倍,显然在业务数据表上直接建索引更可取。当然,Salesforce的情况可能有其历史原因,或者它有某种未知的核武器。本文建议采用如下模型:

从业务数据库到元数据,SaaS架构设计经验全总结 10

其实,Salesforce对于查询是有限制的,如果它消耗的资源太大,会直接抛异常。很可能它是依据提取数据的行数的阈值或者时间(governor limits,资源裁判的角色)来限制的,因此它的性能还是有一定的局限性。官网对此表述为:“被优化器认为资源开销过大的个别查询会抛出异常给调用方,尽管这听起来有点严格,但为了保护数据库系统总体的可伸缩性和性能,这是必要的。”

建议五:索引所有字段

Salesforce的做法是让租户自己决定一个字段是否要索引,但笔者认为在硬件越来越廉价的今天,如果要在用户体验与成本之间平衡,用户体验更可取。不过Salesforce也会自动为特定字段建索引,参见这里。

其实软件这东西,从用户接受层面上讲,在根植于中国文化的市场上是有点障碍的。例如:字段field,这个词对于中国大部分普通人来说是很陌生的,但是对于以英语为母语的市场而言,说“请把这个表格填一下”,然后说“包括每一个field”,则是一件很普通的事情。当我们交付一个产品的时候,需要站在用户的角度去体验、思考、感受,而不能假设所有人都有和软件开发人员一样的认知背景。

建议六:PostgreSQL优于MySQL

这里不是要对二者做详尽的比较,而是瞄准一个核心点,元数据驱动的定制能力。由于MySQL的row size是有限制的,65535字节,而PostgreSQL的限制则为1GB,显然后者有更广阔的空间,这也是推荐图 10业务数据模型的原因之一。

建议七:深挖数据库本身的优化空间

对于PostgreSQL,相信还有很多潜力可以挖掘,笔者暂未对其做过深入研究,这里只给出一个方向。例如:它支持sub-partition,假设在用OrgID分区的前提下,再进一步用年来分区,对于有些数据的性能可能会更进一步提升,不过无法保证这个可行,凡有得必有失。

再比如,在MySQL中,通常可能认为插入一条数据没啥可优化的,就是通常见到的那种写法,但是,insert into table_1 set a=a1,b=b2这样的写法据说是最高效的。

诸如此类,结合多租户、元数据驱动的特点,可能还有很多值得挖掘的地方,最可靠的方法是完整研读官网、对多种值得关注的选项动手试一试。

2 搜索

搜索是SaaS必须具备的一种能力,例如:输入关键词,希望系统能找出附件中出现这些关键词的合同,不管附件的格式如何。搜索和通常RDBMS的全文检索是完全不同的,尽管在某些技术思路上是一样的,但具体实现的能力差别很大。因此,SaaS系统必须提供存在于关系型数据库之外单独的搜索系统。

这里仍以Saleforce为例展开说明。Salesforce对于空间非常吝啬,对于任何一个用户自定义字段,是否建索引、是否可以搜索,都把选择权留给用户。其实这么做从用户体验上看并不好,而且对于普通用户,一般对于搜索与查询没有很强的技术性概念,在选择时就会存在困惑。因此,更可取的做法可能是,对于可能需要搜索的,就让它都能搜索。但是,有一个基本的问题要回答,那就是结果集从哪里来?

从业务数据库到元数据,SaaS架构设计经验全总结 11

如果结果集中同时包含来自关系型数据库和搜索引擎的数据,并让用户在定制过程中选择各个字段的结果都从哪里来,对用户体验可能不大好。但我们可以这么做,让最终用户在已经完成定制并发布的功能中选择,在高级查询界面专门开辟出搜索条件区域,让用户输入关键词和搜索范围即可。

上图左侧的模式,搜索引擎返回的是ID列表,需要组合两个引擎的能力。这就要求平台有自己的查询引擎和优化器,基本逻辑是先识别出搜索部分,然后把结果组装到原来的查询语句中,最后提交给RDBMS来处理。

这里补充一个建议,对于用户上传的附件,只要可以转换为文本,也把它送到搜索引擎,用户在定义业务实体的时候可以不指定要不要可搜索,但是在构建查询功能的时候,可以由用户来决定是不是对某些字段执行搜索。

由于目前的开源搜索引擎(至少Elasticsearch是这样的)还不能保证聚合的准确性和不丢失数据,因此对于潜在的丢失数据的问题,在架构上可以考虑:

从业务数据库到元数据,SaaS架构设计经验全总结 12

3 元数据

把对元数据的理解局限于表及其属性、字段及其属性,是不够的。其实把元数据称为模型驱动更合适,它可以包含PaaS或SaaS中那些所有由客户自己创建的软件要素的模型,例如:邮件模型、界面模型、布局模型、API模型、流程模型等。其实人类认识世界、改造世界,根本上就是一个模型提出、验证、运用的过程。这个世界会越来越由数据驱动,背后实际上就越来越是由模型驱动。如果一个PaaS或SaaS由外到里都是模型驱动的,那它的定制能力一定很强,适应、生存、发展的能力也一定会很强,因为不管需要什么都可以直接用PaaS来生产,就像一个超级生产线,非常规范。

关于版本控制,在PaaS上定制的一切都可以看作配置,它们都需要版本控制能力,颗粒度可以由粗到细,当然这也要求为用户提供非生产环境,下面会提到。

4 环境

人都有可能犯错,而改变就需要测试和验证,虽然我们赋予了用户定制的能力,但直接修改生产环境可能意味着不可恢复的风险。不论是SaaS还是PaaS,都显然不妥。另外,用户可能自己定制出很复杂的应用,而要用到它的新员工需要培训,可是显然不可能通过实际操作来进行培训。因此,很有必要为客户提供非生产环境,这一点Salesforce做得非常到位,值得学习。这也是差异化利润点,其各种环境的主要区别在于有没有生产数据、有多少。

5 后台进程组件

从业务数据库到元数据,SaaS架构设计经验全总结 13

上图中架构的主旨是为了实现零编码,该架构最终实现的PaaS的目标受众是Citizen Developer,即没有IT背景的人。也就是说后台逻辑是完全由配置驱动的或者说声明式的,并且要可视化地、以拖拽方式完成后台逻辑的设计。虽然没办法说它能实现所有的后台逻辑(因为理论上逻辑是有无限可能的),但是,它所能做的范围已经可以覆盖绝大部分情况了。有人可能会说,后台逻辑中的循环逻辑、分支逻辑怎么办呢?这也是可配置的。从技术上讲,就如何满足后台的定制需求这一点来讲,Salesforce有自己的编程语言Apex、自己的Query Language和Search Language,但个人觉得这都是面向程序员的,不够好,本文建议零编码,真正做到For Citizen Developer。

当一个请求经过网关到达一个服务进程以后,在这个进程里发生的所有事都是由Process Engine总控的。其最为核心的抽象是,输入的对象、本地调用或者远程调用返回的结果,或者本地子过程的处理结果都是有名称的、可引用的、可以通过属性路径来操作的对象,而这个对象的结构是任意的,如图中的input和result_*。概括起来讲,就是内存里的所有数据都是声明方式可操作的。

从大的方面看,这个PaaS核心架构,有一种情况不能满足,那就是微服务。如果客户要求存储独立的微服务,那是做不到的,对客户的系统设计能力要求相应地也比较高。其实微服务更多是给研发用的,客户一般并不关心。对于一个租户而言,微服务真正有意义的地方在于,业务所要求的数据处理能力已经超出了一个关系型数据库实例的上限。这样的话,可能更可取的方式是,看如何在一个租户范围内实现写操作的分区(可以设计为图 14)。不过那就太大了,如果一个租户都达到这样一个系统要求的量级了,可能不应该找SaaS或PaaS供应商,而只能另觅他途了。

从业务数据库到元数据,SaaS架构设计经验全总结 14

作为SaaS或PaaS供应商,如果用微服务,可以考虑把人员组织机构、第三方服务的调用、报表等独立出来,剩下的都是客户的业务,在单体应用中处理即可。

协议建议采用HTTP2,它是多工(mutiplex)的,且服务端可推。即使内部使用,因为HTTP2已经很快了,足够用,简单就是美。

再稍微提一下区块链,区块链最根本的地方是关于信任的,一般SaaS是关于企业内部活动的(intro-company),但是如果SaaS供应方把业务扩展到企业之间的行为(inter-company),也许区块链就有用武之地了,而入驻的企业就能变得既隔离又联结。

审计,To B的应用相对于To C的应用往往是更严肃、更讲究责任的,为此,建议至少做到记录级的审计,5W(who/where/when/what/how)。

权限,企业应用离不开权限管理,有没有考虑到集团化的企业呢?多个分公司、子集团,各个分支机构之间在很多领域是相互隔离的,但也有可能是相通的。数据权限怎么处理?能由集团的超级管理员来总控分公司的管理员吗?支持阿米巴组织吗?SaaS要走远、要做大,诸如此类的问题恐怕是不可避免的,当然可以先放在低优先级去实现,但是在设计上必须支持才好。

6 前端

写到这里,对于个性的满足就剩前端了,这里简单给出建议:

  • 使用与后端相同的数据模型;
  • 封装自己的控件,模型如下图所示,有的时候共享dataset会让有些事情处理起来变得很方便,页面内有全局的dataset管理就更好了;

从业务数据库到元数据,SaaS架构设计经验全总结 15

  • On demand,或者懒加载,需要了再请求,不要从后台一次提取页面可能需要的全量数据,其实很多情况下实际是在让后台做无用功;
  • 但凡用户设置的,都在元数据的管理范围之内,要让满足个性化需求这件事情完全由数据驱动的,不管是企业的个性还是用户的个性;
  • 页面内逻辑实现也可以是基于元数据的,也就是说页面内的逻辑也是可定制的,即使实现起来有点复杂。

总结

本文的核心是聚焦于SaaS如何满足个性化需求,由此引出PaaS,并不是定位于成为PaaS Vendor,后者可能还需要扩展到数据仓库、实时数据仓库、流式计算、机器学习、数据中台、数据应用、图计算、IoT等方面。不过这些除了选择合适的中间件,在平台中实现连接件,剩下的用户通过自服务实现所需定制构件的方法与文中提到的没有很大差异,换句话说,仅为量变。假设定位为PaaS Vendor,本文分享的方法也是适用的,每个扩展领域只是商业上值不值的问题。

不过,如果边界划到满足SaaS的需要,可以扩展到由用户决定要不要微服务、要不要独立的报表服务(包括独立的库)两个方面。再想提一点的是,做SaaS,一定要做好与客户既有系统、或可能的外在系统的集成,这对于SaaS供应商而言意味着数据双向的流动。

另外,要让系统合规,例如:GDPR规范,国家标准或行业标准,尤其是数据治理、安全方面,虽然本文已经建议做到记录级的审计,但还是需要认真研究一下有关标准。

最后想跟大家分享几条架构心得,这些也是笔者在写本文的过程中考虑到的一些思想,虽然和SaaS没有直接联系,但假如实践中真的能够以如下思想为纲,必有受益。以下内容不成体系,想哪写哪,希望对大家在思考具体问题的时候能有帮助。

  • Solve the business problem,不要片面地停留在技术层面,业务战略、业务架构、业务发展诉求的满足等业务层面的认知与探究才是第一位的,要以业务为始、以业务为终;
  • One place, once for all,最好能够在一个地方、一次性地解决一类问题,而不是头疼医头脚疼医脚,这是衡量一个架构好坏的准绳之一;
  • 站在巨人肩膀上,先学习人家是怎么做的,验证是否效果最好,摈弃权威思维定式;
  • 不是功能有了,就一切都有了,那样到后来很可能就跑不动了。要动手做基础研究,切忌跟风,一定要根据业务自己动脑子思考,心里明白真正要什么,往往真正要的不是框架本身,跑得快、可能欠下很多债,乃至积重难返。火车启动慢,一旦跑起来其能量不是任何摩托车可比的,就像下围棋一样,局布得不好,迟早会为其买单;
  • 业务、业务、抽象、抽象,抽象(abstract)这个词来源于古希腊,意思是去掉细节。不要一开始就太纠结于具体技术、框架,如果思维的焦点大部分都是这些东西,作为架构师是彻底把方向搞反了,其实务虚比务实更重要,如果事情已经推进到了涉及具体技术的阶段,那已经不是大问题了。这并不是说不主张get your hands dirty on something,而是讲什么更重要、什么是先导、什么服从于什么,这也是为什么一个高端的岗位更需要一个更注重修为、有思想的人;
  • 早先大家用黑白照相机,然后有了彩色相机,现在用手机似乎就可以拍出不错的照片,可是照的好的还是摄影师。这是一个类比,随着技术生态的发展,各种框架不断涌现,就好比是傻瓜相机,但做架构不是去学会如何按那个快门,不是去拼盘、攒框架,如果仅仅是那样,就不是玩技术了,而是被技术玩了。可能有不少人以技艺自居,舍本逐末,不练思维,为技而动,这是做不好架构的。现在网络如此发达,知识唾手可得,就具体技术而言,不知、不会其实都不是太大的问题,真正的问题是如何全面、透彻地思考业务,然后在纯抽象的层面明确地定义到底要什么、具体的架构目标是什么,然后才进入到技术选型阶段。架构相对于开发是一个谋大于动的工作,做软件不是人越多越好、越强,而是要想着如何用最少的人做更大的事;
  • 做一个强大的PaaS,完全可以雇一些类似富士康生产线上的人,经过完整培训,然后就可以高效、高质量地生产包括SaaS在内的大部分软件了,即使需要承受很大的并发、覆盖复杂的业务逻辑。国内制造业的核心、高端技术,放眼望去,其实挺贫瘠的,软件业更是如此。其实软件的品控远远没有制造业做得好,原因在于最终交付物中个人因素太多了,越多越不可控,而PaaS大大限制了开发者的自由裁量权,而且内在逻辑完全是可控的,因此质量一定比通常的开发模式高许多,且会累积性地提高,开发者不是质量的变量,这要求不只是低代码(Low Code),而是零代码(Zero Code);
  • 意识,人们常说要有某种意识,对于架构而言,要加怎样的定语呢?建议:业务、客户、服务、体验、效率、成本、风险。架构工作的起点是业务的现状(baseline),然后要扩展到业务发展目标(target)、系统现状、团队现状,再到系统目标、整个信息化数字化的目标,这样才可能有清晰的架构发展路线图与里程碑,而这些意识要贯彻到整个过程中。