Why SaaS?
过去两年里,疫情影响下企业数字化进程加速发展,SaaS行业得到催化,与此同时SaaS赛道获得了众多风投的青睐,多个细分垂直SaaS厂商获得亿级别以上投资, 如售后宝、班牛等。相较于发达国家,国内SaaS水平相对较低,且行业也集中于电商、零售等不多的行业,导致风投主要也集中于电商或相关领域,以掌上先机(旺店通)为例,去年D轮获软银领投3.12亿美元融资,创国内2021年SaaS单笔融资金额最高记录。
SaaS为何突然收到如此大的关注?关于SaaS的商业模式讨论,互联网上有很多,结论不一一列举,总的来说,SaaS走的是“复制规模化+标准化”的路线,用某独角兽电商ERP SaaS创始人的话来说:“我们用10%的价格解决商家的90%问题,所以我们不和AA、 BB去拼定制功能!”(注:AA,BB是电商ERP子领域的定制化SaaS厂商),从中可以窥见,SaaS商业模式是标准化下进行大规模复制,形成规模效应。
多租户设计模式(Mutli-Tenant Design Pattern)
SaaS厂商构建服务具有规模效应,尤其是规模越大,成本越低,对资源的合理复用,同时合理利用云厂商提供的资源实现动态弹性,能够降低资源总体持有量,同时提升使用率,同时对多租户的资源进行动态整合和分配,能进一步降低总成本。
为了实现资源复用和公用,在数据库层,通过一定的规则进行租户路由将租户映射到具体的业务数据库中,在数据库上实现多个租户共用和复用,从而提升使用率,降低单个租户的使用成本。
N个鸡蛋放在M个篮子里?
在SaaS软件进行租户路由时,如同将N个鸡蛋放在不通的M个篮子里面,首先考虑放不放得下的问题,然后考虑鸡蛋在篮子内的排列方式,还得考虑篮子大小规格,篮子总体积是否足够小...等各个限制条件,当然,鸡蛋和篮子的个数和大小也是变化的。
在数据库层面,多租户采取的方案,需要考虑以下因素:
- 隔离性
- 扩展性
- 租户成本
- 运维复杂性
- 隔离性
隔离性是在指租户之间性能和数据是否隔离,性能主要是指一个租户的负载是否会影响到其他租户,在合理的成本下减少嘈杂邻居(Noisy Neighbor)现象,尤其大租户会不会受到影响。在SaaS商业模型中,一般大租户服务的SLA(Service Level Agreement)是需要优先考虑的,毕竟大租户/客户对SaaS厂商来说,不管是营收、口碑和需求等方面考虑,都是优先保障的。数据隔离一般是大租户对数据安全有特定的需求,比如等保,需要数据单独存储,是否需要加密等等。
由于系统是动态负载的,租户事先资源评估和压测可以一定程度上防止嘈杂邻居的问题,但是在现实情况下真正发生隔离性问题后,如何快速解决隔离性问题也是影响多租户设计的重要考量,尤其对于数据库来说,问题更为棘手,数据库作为一个有状态的服务,即使在云环境下,快速做到快速升级(scale up? or scale out?)来解决隔离性问题相较于无状态的服务来说更为困难。
- 扩展性
扩展性包含多个层面,从租户层面来说,租户随着业务发展,小租户数据量逐步多,可能会发成大租户,对应商业上可能是购买更高级版本的服务,历史数据库是否能够持续使用,迁移期间服务是否可用/中断等。
对于SaaS厂商来说,扩展性主要考虑以下几个因素:
1、SaaS多个商业化版本之间是否兼容,不同的版本对应的数据库schema设计能够做到向下/低兼容,国内SaaS厂商数据库一般使用开源MySQL和PostgreSQL。
2、当数据库资源达到警戒水位,需要考虑是否需要将租户进行迁移到更好的数据库资源还是原地升级更高规格?
3、租户拆分和合并是否容易,能否自动化,数据库迁移能否快速完成?
4、当前架构下,单个实例最大能支持的QPS和TPS? 是否超过单机实例处理上限?是否需要进行拆分,是进行垂直拆分还是水平拆分?拆完之后如何和现有的软件开发和运维保持一致?
5、当新租户加入时,提供新的实例还是在已有实例中寻找最大空闲资源?还是新开数据库实例?
6、一般SaaS厂商也提供OLAP查询,底层使用的OLAP查询能否具有横向扩展能力,以及具有弹性能力?让SaaS厂商在发展过程中更多关注业务发展,在SaaS厂商在不同的发展阶段尽量使用同一套底层架构。
- 租户成本
SaaS通过规模效应,相较于传统软件具有很大优势,关于这部分对比很多相关文章可以参考,总的来说SaaS厂商需要将本增效,在保证SLA前提下尽量降低资源持有和使用成本,在数据库层面保证一定的水位,防止突发大流量,同时保持RT在合理水平上。
综上考虑以下几个因素:
1、单实例上租户数量,SaaS厂商希望将单实例上的租户的数量保持在一个相对高的水平,通过复用来减少固定资源开销;
2、存储成本,由于数据历史性缘故,历史数据查询和修改概率较低,通过合理设置冷热数据比例来减少热数据常用存储量;
3、资源水位,将CPU、IO和存储保持在一个合理的水位上,尽量不浪费;
4、结合业务特性,合理规划业务高峰,面对“定时”的大流量,例如电商ERP业务商家一般会在下午3-5点进行发货,对数据库IO读取要求比较高,通过临时弹升而不是长期持有大量资源能够降低成本。
上述的一些因素主要考虑静态环境下,单租户的成本,而动态评估租户效能,需要结合租户隔离、存储成本、使用画像(业务量)和服务级别(SLA)/软件价格来综合评估,在与SaaS厂商沟通过程中,各家都有一定的尝试,一般都是基于规则或者启发式(heuristic),这部分我们也正在尝试与部分头部的SaaS厂商共建。
- 运维复杂性
作为标准化SaaS,服务的客户较多,即使在多租户设计下,数据库使用量都在数百至数千个不等,监控和运维这么多数据库实例需要尽量做到自动化,虽然云厂商提供了底层的数据库运维和监控,将DBA从繁杂的工作中解脱出来,但是配合业务上的数据变更和数据发布对DBA来说也是一个很大工作量,从SaaS厂商来说,新租户加入和老租户的退出同样要做相应的生命周期管理。
在多租户架构设计下,数据库运维主要考虑以下几个因素:
1、新加实例/租户后,数据库是否/如何初始化?
2、租户迁移合并等涉及租户对应的数据库变更,是否自动化,能否有自动化脚本支持?
3、数据恢复,针对单租户的备份和恢复是否方便,部分SaaS厂商针对租户的数据库恢复进行了商业化,因此对备份和恢复速度有强需求。
结合SaaS厂商开发能力,所处的阶段,运维能力等多种因素,总体来看使用以下几种数据库架构模式:
DB隔离
一个租户使用一个DB,甚至使用一个instance,这种方式简单明了,大小租户统一管理,迁移也比较容易,相对来说解决隔离性问题也较容易解决,但是这种管理方式带来的问题是元数据较多,例如ERP这种偏数据库重操作的应用,每个租户一套表,表的数目较大,对后期运维,例如DDL等比较麻烦。
DB隔离模式在大租户场景下非常适用,同时资源评估和效能估计也是比较容易。
表隔离
表隔离模式,主要是多个租户公用一个DB,公共数据(例如国家地区代码)使用同一套表,而每个租户的业务数据分别使用不同的表,业务表名一般会带上租户ID。
表隔离模式,在元数据上总量比DB隔离方式会少。租户迁移需要制定到具体表,迁移的自动化代码需要随着业务变化进行修改,运维成本偏高。
行隔离
行隔离模式,主要是多个租户公用一个DB,而每个租户的业务数据使用同一套表,表的每一行都会带上租户ID,在业务上每次CRUD都会带上租户ID。
行隔离模式,隔离性比较差,尤其是当多个大租户一起向同一个类业务写入/读取数据时,存在一定资源争用,同时数据迁移也需要带相应的租户ID。
行隔离模式现实中的优势,以电商场景为例子,SaaS厂商可以通过建立一批订单表(例如基表数目table_base_number = 256),可以根据租户ID和订单号Hash方式(例如 MOD (table_base_number )写入到业务表,从一定程度上避免了大表,后续需要扩大表的数量时,修改对应的table_base_number即可。在DB隔离模式和表隔离模式下,订单流水表容易出现大表,如果进行二次分表,如按照不同的租户类别按照订单流水量设置不同的分表规则,在业务开放上会引入复杂度,同时在一些聚合类查询中需要聚合多张表的结果。
综上,在常用的SaaS厂商数据库架构下,一般采取的隔离方案对比如下
DB隔离 |
表隔离 |
行隔离 |
|
隔离性 |
优 |
良 |
差 |
扩展性 |
中 |
中 |
良 |
租户成本评估 |
优 |
良 |
差 |
运维复杂性 |
优 |
良 |
差 |
多租户部署模式(Mutli-Tenant Deployment Pattern)
在合理的成本下,如何容纳更多租户,并且保证服务的SLA?我们先来看下SaaS厂商一般的商业模式和客户分布的基础情况,
上图来源电商SaaS上市第一股光云财报,如上图所示,“金字塔结构的底层为数量最多、规模较小的初创型商家,该等商家未来不确定性较大,对电商SaaS产品处于摸索阶段,需求较为简单和基础,且对产品价格高度敏感;中层为发展中商家,该等企业已具备较为稳定的业务模式,对电商SaaS产品形成了一定黏性,但受限于自身业务规模投入预算有限,因此对性价比较高的垂直细分领域电商SaaS产品表现出较高的需求;顶层为少量成熟型商家和品牌型商家,该等商家在资金、获客渠道、供应链管理等方面具备明显的竞争优势,希望通过专业性更强的SaaS产品增强内部经营管理效率并提升盈利能力,对价格的敏感性较低,而更加注重产品效果。
其中,成熟型商家和品牌型商家具有较高的客户稳定性、较多的垂直细分功能需求性以及较强的支付购买力,是电商SaaS企业重点争取的客户群体。未来,随着市场竞争的深入,成熟型商家和品牌型商家在电商行业的竞争优势将愈发明显,聚焦成熟型及品牌型商家需求、争夺该类客户资源是市场的必然趋势。”
我们可以看到商家/租户分布,初创型商家、发展型商家、成熟型商家、品牌型商家数量逐步减少,而对应的ARPU逐步上升,相应地对于数据库隔离性以及性能要求逐步变高,因此SaaS厂商也是会分配的更好的资源,结合上面的数据库隔离架构模式,在部署上会采用单租户单独部署和多租户共享部署方式。
单租户单独部署一般是面向头部大租户,尽可能降低其他租户的影响,保障对头部大租户的服务,在部分情况下,按照客户要求单独部署到客户要求的环境中。
租户迁移
在多租户共享实例情况下,不管是实例容量不足、租户等级变化等,将租户迁移到其他实例上在SaaS场景下非常常见,考虑到SaaS厂商提供的服务一般都7*24,所以一般数据迁移是实时在线,等源数据和目标数据对齐后,进行切换。以MySQL数据库为例,在云上一般使用DTS,或者开源的工具canal进行实时同步。
在租户数据同步过程中,一般使用脚本进行一键迁移,相应地:
1、DB隔离模式下最简单,选择一键迁移整个库:
2、表隔离模式下,迁移所需要的表,由于通常使用业务二次分表以及schema变更,相应的同步脚本中涉及的表也需要变更,通常通过数据库Devops可以将这部分脚本进行自动化同步;
3、行隔离模式,在表隔离模式下,需要在对应的表上加上过滤条件(租户ID = XXX)来进行设置;
小结
在SaaS场景下,我们讨论了常用的数据库多租户构架,以及常用的部署模式,初步讨论了这些架构背后的考量,是多种因素下综合权衡的结果,而软件的艺术之美源于权衡(tradeoff)。
参考
1、《设计数据密集型应用》https://github.com/Vonng/ddia